@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,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Sponsors and Marketplace Billing
|
|
3
|
+
*
|
|
4
|
+
* Types and utilities for GitHub-based monetization.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Praxis Cloud subscription tiers
|
|
9
|
+
*/
|
|
10
|
+
export enum SubscriptionTier {
|
|
11
|
+
/**
|
|
12
|
+
* Free tier - limited usage
|
|
13
|
+
*/
|
|
14
|
+
FREE = "free",
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Solo tier - individual developers via GitHub Sponsors
|
|
18
|
+
*/
|
|
19
|
+
SOLO = "solo",
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Team tier - small teams via GitHub Sponsors
|
|
23
|
+
*/
|
|
24
|
+
TEAM = "team",
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Enterprise tier - self-service enterprise via GitHub Sponsors/Marketplace
|
|
28
|
+
*/
|
|
29
|
+
ENTERPRISE = "enterprise",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Billing provider type
|
|
34
|
+
*/
|
|
35
|
+
export enum BillingProvider {
|
|
36
|
+
/**
|
|
37
|
+
* GitHub Sponsors
|
|
38
|
+
*/
|
|
39
|
+
SPONSORS = "sponsors",
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* GitHub Marketplace (SaaS)
|
|
43
|
+
*/
|
|
44
|
+
MARKETPLACE = "marketplace",
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Free tier (no billing)
|
|
48
|
+
*/
|
|
49
|
+
NONE = "none",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Subscription status
|
|
54
|
+
*/
|
|
55
|
+
export enum SubscriptionStatus {
|
|
56
|
+
/**
|
|
57
|
+
* Active subscription
|
|
58
|
+
*/
|
|
59
|
+
ACTIVE = "active",
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Subscription cancelled, but still valid until period end
|
|
63
|
+
*/
|
|
64
|
+
CANCELLED = "cancelled",
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Subscription expired or payment failed
|
|
68
|
+
*/
|
|
69
|
+
EXPIRED = "expired",
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* No subscription
|
|
73
|
+
*/
|
|
74
|
+
NONE = "none",
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Tier limits for different subscription levels
|
|
79
|
+
*/
|
|
80
|
+
export interface TierLimits {
|
|
81
|
+
/**
|
|
82
|
+
* Maximum sync operations per month
|
|
83
|
+
*/
|
|
84
|
+
maxSyncsPerMonth: number;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Maximum storage in bytes
|
|
88
|
+
*/
|
|
89
|
+
maxStorageBytes: number;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Maximum number of team members (null = unlimited)
|
|
93
|
+
*/
|
|
94
|
+
maxTeamMembers: number | null;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Maximum number of apps/projects
|
|
98
|
+
*/
|
|
99
|
+
maxApps: number;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Support level
|
|
103
|
+
*/
|
|
104
|
+
supportLevel: "community" | "standard" | "priority";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Subscription information
|
|
109
|
+
*/
|
|
110
|
+
export interface Subscription {
|
|
111
|
+
/**
|
|
112
|
+
* Subscription tier
|
|
113
|
+
*/
|
|
114
|
+
tier: SubscriptionTier;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Subscription status
|
|
118
|
+
*/
|
|
119
|
+
status: SubscriptionStatus;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Billing provider
|
|
123
|
+
*/
|
|
124
|
+
provider: BillingProvider;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* GitHub sponsor tier ID (if applicable)
|
|
128
|
+
*/
|
|
129
|
+
sponsorTierId?: string;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* GitHub Marketplace plan ID (if applicable)
|
|
133
|
+
*/
|
|
134
|
+
marketplacePlanId?: number;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Subscription start date
|
|
138
|
+
*/
|
|
139
|
+
startDate: number;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Current period end date
|
|
143
|
+
*/
|
|
144
|
+
periodEnd?: number;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Whether subscription auto-renews
|
|
148
|
+
*/
|
|
149
|
+
autoRenew: boolean;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Usage limits for this tier
|
|
153
|
+
*/
|
|
154
|
+
limits: TierLimits;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Billing event type
|
|
159
|
+
*/
|
|
160
|
+
export interface BillingEvent {
|
|
161
|
+
/**
|
|
162
|
+
* Event type
|
|
163
|
+
*/
|
|
164
|
+
type: "subscription_created" | "subscription_cancelled" | "subscription_renewed" | "tier_changed";
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Timestamp
|
|
168
|
+
*/
|
|
169
|
+
timestamp: number;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* User/organization ID
|
|
173
|
+
*/
|
|
174
|
+
userId: number;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Old subscription (for changes)
|
|
178
|
+
*/
|
|
179
|
+
oldSubscription?: Subscription;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* New subscription
|
|
183
|
+
*/
|
|
184
|
+
newSubscription: Subscription;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Default tier limits
|
|
189
|
+
*/
|
|
190
|
+
export const TIER_LIMITS: Record<SubscriptionTier, TierLimits> = {
|
|
191
|
+
[SubscriptionTier.FREE]: {
|
|
192
|
+
maxSyncsPerMonth: 1000,
|
|
193
|
+
maxStorageBytes: 10 * 1024 * 1024, // 10 MB
|
|
194
|
+
maxTeamMembers: 1,
|
|
195
|
+
maxApps: 1,
|
|
196
|
+
supportLevel: "community",
|
|
197
|
+
},
|
|
198
|
+
[SubscriptionTier.SOLO]: {
|
|
199
|
+
maxSyncsPerMonth: 50000,
|
|
200
|
+
maxStorageBytes: 1024 * 1024 * 1024, // 1 GB
|
|
201
|
+
maxTeamMembers: 1,
|
|
202
|
+
maxApps: 10,
|
|
203
|
+
supportLevel: "standard",
|
|
204
|
+
},
|
|
205
|
+
[SubscriptionTier.TEAM]: {
|
|
206
|
+
maxSyncsPerMonth: 500000,
|
|
207
|
+
maxStorageBytes: 10 * 1024 * 1024 * 1024, // 10 GB
|
|
208
|
+
maxTeamMembers: 10,
|
|
209
|
+
maxApps: 50,
|
|
210
|
+
supportLevel: "standard",
|
|
211
|
+
},
|
|
212
|
+
[SubscriptionTier.ENTERPRISE]: {
|
|
213
|
+
maxSyncsPerMonth: 5000000,
|
|
214
|
+
maxStorageBytes: 100 * 1024 * 1024 * 1024, // 100 GB
|
|
215
|
+
maxTeamMembers: null, // unlimited
|
|
216
|
+
maxApps: 1000,
|
|
217
|
+
supportLevel: "priority",
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Check if a user has access to a specific tier
|
|
223
|
+
*/
|
|
224
|
+
export function hasAccessToTier(
|
|
225
|
+
subscription: Subscription,
|
|
226
|
+
requiredTier: SubscriptionTier
|
|
227
|
+
): boolean {
|
|
228
|
+
if (subscription.status !== SubscriptionStatus.ACTIVE) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const tierOrder = [
|
|
233
|
+
SubscriptionTier.FREE,
|
|
234
|
+
SubscriptionTier.SOLO,
|
|
235
|
+
SubscriptionTier.TEAM,
|
|
236
|
+
SubscriptionTier.ENTERPRISE,
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
const currentTierIndex = tierOrder.indexOf(subscription.tier);
|
|
240
|
+
const requiredTierIndex = tierOrder.indexOf(requiredTier);
|
|
241
|
+
|
|
242
|
+
return currentTierIndex >= requiredTierIndex;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Check if usage is within tier limits
|
|
247
|
+
*/
|
|
248
|
+
export function checkUsageLimits(
|
|
249
|
+
subscription: Subscription,
|
|
250
|
+
usage: {
|
|
251
|
+
syncCount: number;
|
|
252
|
+
storageBytes: number;
|
|
253
|
+
teamMembers: number;
|
|
254
|
+
appCount: number;
|
|
255
|
+
}
|
|
256
|
+
): {
|
|
257
|
+
withinLimits: boolean;
|
|
258
|
+
violations: string[];
|
|
259
|
+
} {
|
|
260
|
+
const violations: string[] = [];
|
|
261
|
+
|
|
262
|
+
if (usage.syncCount > subscription.limits.maxSyncsPerMonth) {
|
|
263
|
+
violations.push(
|
|
264
|
+
`Sync limit exceeded: ${usage.syncCount}/${subscription.limits.maxSyncsPerMonth}`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (usage.storageBytes > subscription.limits.maxStorageBytes) {
|
|
269
|
+
violations.push(
|
|
270
|
+
`Storage limit exceeded: ${(usage.storageBytes / 1024 / 1024).toFixed(2)}MB/${(subscription.limits.maxStorageBytes / 1024 / 1024).toFixed(2)}MB`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (
|
|
275
|
+
subscription.limits.maxTeamMembers !== null &&
|
|
276
|
+
usage.teamMembers > subscription.limits.maxTeamMembers
|
|
277
|
+
) {
|
|
278
|
+
violations.push(
|
|
279
|
+
`Team member limit exceeded: ${usage.teamMembers}/${subscription.limits.maxTeamMembers}`
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (usage.appCount > subscription.limits.maxApps) {
|
|
284
|
+
violations.push(
|
|
285
|
+
`App limit exceeded: ${usage.appCount}/${subscription.limits.maxApps}`
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
withinLimits: violations.length === 0,
|
|
291
|
+
violations,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Create a free tier subscription
|
|
297
|
+
*/
|
|
298
|
+
export function createFreeSubscription(): Subscription {
|
|
299
|
+
return {
|
|
300
|
+
tier: SubscriptionTier.FREE,
|
|
301
|
+
status: SubscriptionStatus.ACTIVE,
|
|
302
|
+
provider: BillingProvider.NONE,
|
|
303
|
+
startDate: Date.now(),
|
|
304
|
+
autoRenew: true,
|
|
305
|
+
limits: TIER_LIMITS[SubscriptionTier.FREE],
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Create a subscription from GitHub Sponsors tier
|
|
311
|
+
*/
|
|
312
|
+
export function createSponsorSubscription(
|
|
313
|
+
tierName: string,
|
|
314
|
+
monthlyPriceInCents: number
|
|
315
|
+
): Subscription {
|
|
316
|
+
let tier = SubscriptionTier.FREE;
|
|
317
|
+
|
|
318
|
+
// Map price to tier (example pricing)
|
|
319
|
+
if (monthlyPriceInCents >= 5000) { // $50/month
|
|
320
|
+
tier = SubscriptionTier.ENTERPRISE;
|
|
321
|
+
} else if (monthlyPriceInCents >= 2000) { // $20/month
|
|
322
|
+
tier = SubscriptionTier.TEAM;
|
|
323
|
+
} else if (monthlyPriceInCents >= 500) { // $5/month
|
|
324
|
+
tier = SubscriptionTier.SOLO;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
tier,
|
|
329
|
+
status: SubscriptionStatus.ACTIVE,
|
|
330
|
+
provider: BillingProvider.SPONSORS,
|
|
331
|
+
sponsorTierId: tierName,
|
|
332
|
+
startDate: Date.now(),
|
|
333
|
+
autoRenew: true,
|
|
334
|
+
limits: TIER_LIMITS[tier],
|
|
335
|
+
};
|
|
336
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud Relay Client
|
|
3
|
+
*
|
|
4
|
+
* Client for connecting to Praxis Cloud Relay service (Azure-based).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
CloudRelayConfig,
|
|
9
|
+
CloudRelayClient,
|
|
10
|
+
RelayStatus,
|
|
11
|
+
CRDTSyncMessage,
|
|
12
|
+
UsageMetrics,
|
|
13
|
+
HealthCheckResponse,
|
|
14
|
+
} from "./types.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a cloud relay client
|
|
18
|
+
*/
|
|
19
|
+
export function createCloudRelay(config: CloudRelayConfig): CloudRelayClient {
|
|
20
|
+
let status: RelayStatus = {
|
|
21
|
+
connected: false,
|
|
22
|
+
endpoint: config.endpoint,
|
|
23
|
+
appId: config.appId,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
let syncTimer: NodeJS.Timeout | null = null;
|
|
27
|
+
const vectorClock: Record<string, number> = {};
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
async connect(): Promise<void> {
|
|
31
|
+
// Validate endpoint
|
|
32
|
+
if (!config.endpoint) {
|
|
33
|
+
throw new Error("Cloud relay endpoint is required");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Test connection
|
|
37
|
+
try {
|
|
38
|
+
const response = await fetch(`${config.endpoint}/health`, {
|
|
39
|
+
method: "GET",
|
|
40
|
+
headers: {
|
|
41
|
+
"Content-Type": "application/json",
|
|
42
|
+
...(config.authToken && {
|
|
43
|
+
Authorization: `Bearer ${config.authToken}`,
|
|
44
|
+
}),
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new Error(`Health check failed: ${response.statusText}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
status.connected = true;
|
|
53
|
+
status.lastSync = Date.now();
|
|
54
|
+
|
|
55
|
+
// Start auto-sync if enabled
|
|
56
|
+
if (config.autoSync) {
|
|
57
|
+
const interval = config.syncInterval || 5000;
|
|
58
|
+
syncTimer = setInterval(() => {
|
|
59
|
+
// Auto-sync logic would go here
|
|
60
|
+
// For now, just update lastSync
|
|
61
|
+
status.lastSync = Date.now();
|
|
62
|
+
}, interval);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
status.connected = false;
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Failed to connect to cloud relay: ${error instanceof Error ? error.message : String(error)}`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
async disconnect(): Promise<void> {
|
|
73
|
+
if (syncTimer) {
|
|
74
|
+
clearInterval(syncTimer);
|
|
75
|
+
syncTimer = null;
|
|
76
|
+
}
|
|
77
|
+
status.connected = false;
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
async sync(message: CRDTSyncMessage): Promise<void> {
|
|
81
|
+
if (!status.connected) {
|
|
82
|
+
throw new Error("Not connected to cloud relay");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Update vector clock
|
|
86
|
+
vectorClock[config.appId] = (vectorClock[config.appId] || 0) + 1;
|
|
87
|
+
message.clock = { ...vectorClock };
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const response = await fetch(`${config.endpoint}/sync`, {
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: {
|
|
93
|
+
"Content-Type": "application/json",
|
|
94
|
+
...(config.authToken && {
|
|
95
|
+
Authorization: `Bearer ${config.authToken}`,
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify(message),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
throw new Error(`Sync failed: ${response.statusText}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
status.lastSync = Date.now();
|
|
106
|
+
|
|
107
|
+
// Merge received vector clock
|
|
108
|
+
const result = await response.json() as any;
|
|
109
|
+
if (result.clock) {
|
|
110
|
+
Object.entries(result.clock).forEach(([key, value]) => {
|
|
111
|
+
vectorClock[key] = Math.max(
|
|
112
|
+
vectorClock[key] || 0,
|
|
113
|
+
value as number
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Failed to sync: ${error instanceof Error ? error.message : String(error)}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
async getUsage(): Promise<UsageMetrics> {
|
|
125
|
+
if (!status.connected) {
|
|
126
|
+
throw new Error("Not connected to cloud relay");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const response = await fetch(
|
|
131
|
+
`${config.endpoint}/usage?appId=${config.appId}`,
|
|
132
|
+
{
|
|
133
|
+
method: "GET",
|
|
134
|
+
headers: {
|
|
135
|
+
"Content-Type": "application/json",
|
|
136
|
+
...(config.authToken && {
|
|
137
|
+
Authorization: `Bearer ${config.authToken}`,
|
|
138
|
+
}),
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
if (!response.ok) {
|
|
144
|
+
throw new Error(`Failed to get usage: ${response.statusText}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return await response.json() as UsageMetrics;
|
|
148
|
+
} catch (error) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Failed to get usage metrics: ${error instanceof Error ? error.message : String(error)}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
async getHealth(): Promise<HealthCheckResponse> {
|
|
156
|
+
try {
|
|
157
|
+
const response = await fetch(`${config.endpoint}/health`, {
|
|
158
|
+
method: "GET",
|
|
159
|
+
headers: {
|
|
160
|
+
"Content-Type": "application/json",
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (!response.ok) {
|
|
165
|
+
throw new Error(`Health check failed: ${response.statusText}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return await response.json() as HealthCheckResponse;
|
|
169
|
+
} catch (error) {
|
|
170
|
+
throw new Error(
|
|
171
|
+
`Failed to get health status: ${error instanceof Error ? error.message : String(error)}`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
getStatus(): RelayStatus {
|
|
177
|
+
return { ...status };
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Connect to Praxis Cloud Relay
|
|
184
|
+
*
|
|
185
|
+
* @param endpoint - Azure Function App endpoint URL
|
|
186
|
+
* @param options - Additional configuration options
|
|
187
|
+
* @returns Cloud relay client instance
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* import { connectRelay } from "@plures/praxis/cloud";
|
|
192
|
+
*
|
|
193
|
+
* const relay = await connectRelay("https://my-app.azurewebsites.net", {
|
|
194
|
+
* appId: "my-app",
|
|
195
|
+
* authToken: "github-token",
|
|
196
|
+
* autoSync: true
|
|
197
|
+
* });
|
|
198
|
+
*
|
|
199
|
+
* // Sync data
|
|
200
|
+
* await relay.sync({
|
|
201
|
+
* type: "delta",
|
|
202
|
+
* appId: "my-app",
|
|
203
|
+
* clock: {},
|
|
204
|
+
* facts: [...],
|
|
205
|
+
* timestamp: Date.now()
|
|
206
|
+
* });
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
export async function connectRelay(
|
|
210
|
+
endpoint: string,
|
|
211
|
+
options: Omit<CloudRelayConfig, "endpoint"> = { appId: "default" }
|
|
212
|
+
): Promise<CloudRelayClient> {
|
|
213
|
+
const config: CloudRelayConfig = {
|
|
214
|
+
endpoint,
|
|
215
|
+
...options,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const client = createCloudRelay(config);
|
|
219
|
+
await client.connect();
|
|
220
|
+
return client;
|
|
221
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Praxis Cloud
|
|
3
|
+
*
|
|
4
|
+
* Cloud relay and synchronization for Praxis applications.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { connectRelay } from "@plures/praxis/cloud";
|
|
9
|
+
*
|
|
10
|
+
* const relay = await connectRelay("https://my-app.azurewebsites.net", {
|
|
11
|
+
* appId: "my-app",
|
|
12
|
+
* authToken: "github-token",
|
|
13
|
+
* autoSync: true
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* // Sync data
|
|
17
|
+
* await relay.sync({
|
|
18
|
+
* type: "delta",
|
|
19
|
+
* appId: "my-app",
|
|
20
|
+
* clock: {},
|
|
21
|
+
* facts: [...],
|
|
22
|
+
* timestamp: Date.now()
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Get usage metrics
|
|
26
|
+
* const usage = await relay.getUsage();
|
|
27
|
+
* console.log(`Syncs: ${usage.syncCount}, Events: ${usage.eventCount}`);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
// Client
|
|
32
|
+
export { createCloudRelay, connectRelay } from "./client.js";
|
|
33
|
+
|
|
34
|
+
// Types
|
|
35
|
+
export type {
|
|
36
|
+
CloudRelayConfig,
|
|
37
|
+
CloudRelayClient,
|
|
38
|
+
RelayStatus,
|
|
39
|
+
CRDTSyncMessage,
|
|
40
|
+
UsageMetrics,
|
|
41
|
+
HealthCheckResponse,
|
|
42
|
+
GitHubUser,
|
|
43
|
+
AuthResult,
|
|
44
|
+
} from "./types.js";
|
|
45
|
+
|
|
46
|
+
// Authentication
|
|
47
|
+
export {
|
|
48
|
+
GitHubOAuth,
|
|
49
|
+
createGitHubOAuth,
|
|
50
|
+
authenticateWithDeviceFlow,
|
|
51
|
+
} from "./auth.js";
|
|
52
|
+
export type { GitHubOAuthConfig } from "./auth.js";
|
|
53
|
+
|
|
54
|
+
// Billing and Subscriptions
|
|
55
|
+
export {
|
|
56
|
+
SubscriptionTier,
|
|
57
|
+
BillingProvider,
|
|
58
|
+
SubscriptionStatus,
|
|
59
|
+
TIER_LIMITS,
|
|
60
|
+
hasAccessToTier,
|
|
61
|
+
checkUsageLimits,
|
|
62
|
+
createFreeSubscription,
|
|
63
|
+
createSponsorSubscription,
|
|
64
|
+
} from "./billing.js";
|
|
65
|
+
export type {
|
|
66
|
+
TierLimits,
|
|
67
|
+
Subscription,
|
|
68
|
+
BillingEvent,
|
|
69
|
+
} from "./billing.js";
|
|
70
|
+
|
|
71
|
+
// GitHub Sponsors
|
|
72
|
+
export {
|
|
73
|
+
GitHubSponsorsClient,
|
|
74
|
+
createSponsorsClient,
|
|
75
|
+
} from "./sponsors.js";
|
|
76
|
+
export type {
|
|
77
|
+
SponsorTier,
|
|
78
|
+
Sponsorship,
|
|
79
|
+
} from "./sponsors.js";
|
|
80
|
+
|
|
81
|
+
// GitHub Marketplace
|
|
82
|
+
export {
|
|
83
|
+
GitHubMarketplaceClient,
|
|
84
|
+
createMarketplaceClient,
|
|
85
|
+
MARKETPLACE_PLANS,
|
|
86
|
+
} from "./marketplace.js";
|
|
87
|
+
export type {
|
|
88
|
+
MarketplacePlan,
|
|
89
|
+
MarketplaceAccount,
|
|
90
|
+
MarketplaceWebhookEvent,
|
|
91
|
+
} from "./marketplace.js";
|
|
92
|
+
|
|
93
|
+
// Auto-Provisioning
|
|
94
|
+
export {
|
|
95
|
+
generateStorageNamespace,
|
|
96
|
+
generateTenantId,
|
|
97
|
+
createTenant,
|
|
98
|
+
validateStorageNamespace,
|
|
99
|
+
getAppStorageContainer,
|
|
100
|
+
provisionTenant,
|
|
101
|
+
getOrCreateTenant,
|
|
102
|
+
} from "./provisioning.js";
|
|
103
|
+
export type {
|
|
104
|
+
Tenant,
|
|
105
|
+
ProvisioningResult,
|
|
106
|
+
} from "./provisioning.js";
|
|
107
|
+
|
|
108
|
+
// Relay endpoints (for Azure Functions deployment)
|
|
109
|
+
export {
|
|
110
|
+
healthEndpoint,
|
|
111
|
+
syncEndpoint,
|
|
112
|
+
usageEndpoint,
|
|
113
|
+
statsEndpoint,
|
|
114
|
+
eventsEndpoint,
|
|
115
|
+
schemaEndpoint,
|
|
116
|
+
} from "./relay/endpoints.js";
|
|
117
|
+
export type {
|
|
118
|
+
AzureContext,
|
|
119
|
+
AzureHttpRequest,
|
|
120
|
+
AzureHttpResponse,
|
|
121
|
+
} from "./relay/endpoints.js";
|