kubetsx 0.1.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.
@@ -0,0 +1,339 @@
1
+ /**
2
+ * 🎯 Kubetsx - Full Stack Example
3
+ *
4
+ * Complete production-ready deployment with:
5
+ * - Multiple microservices
6
+ * - Namespaces
7
+ * - ConfigMaps & Secrets
8
+ * - Autoscaling
9
+ * - RBAC
10
+ *
11
+ * @jsxImportSource ../dist
12
+ */
13
+
14
+ import {
15
+ render,
16
+ Manifest,
17
+ Cluster,
18
+ Namespace,
19
+ Deployment,
20
+ Container,
21
+ Port,
22
+ Env,
23
+ SecretRef,
24
+ ConfigMapRef,
25
+ Resources,
26
+ Probe,
27
+ HttpProbe,
28
+ ExecProbe,
29
+ Service,
30
+ Ingress,
31
+ IngressHost,
32
+ Route,
33
+ ConfigMap,
34
+ Secret,
35
+ Pvc,
36
+ Hpa,
37
+ CronJob,
38
+ ServiceAccount,
39
+ Role,
40
+ RoleBinding,
41
+ Volume,
42
+ VolumeMount,
43
+ EmptyDir,
44
+ PvcVolume,
45
+ } from '../dist/index.js';
46
+
47
+ // ============================================================================
48
+ // Configuration
49
+ // ============================================================================
50
+
51
+ const VERSION = process.env.VERSION || 'latest';
52
+ const ENV = process.env.NODE_ENV || 'production';
53
+ const isProduction = ENV === 'production';
54
+
55
+ // Service definitions - just add to this array to deploy new services!
56
+ const services = [
57
+ {
58
+ name: 'api',
59
+ replicas: isProduction ? 5 : 1,
60
+ port: 3000,
61
+ host: 'api.mycompany.com',
62
+ memory: '512Mi',
63
+ cpu: '500m',
64
+ secrets: ['DATABASE_URL', 'REDIS_URL', 'JWT_SECRET'],
65
+ autoscale: { min: 3, max: 10, cpu: 70 },
66
+ },
67
+ {
68
+ name: 'auth',
69
+ replicas: isProduction ? 3 : 1,
70
+ port: 4000,
71
+ host: 'auth.mycompany.com',
72
+ memory: '256Mi',
73
+ cpu: '250m',
74
+ secrets: ['DATABASE_URL', 'OAUTH_CLIENT_SECRET', 'JWT_SECRET'],
75
+ autoscale: { min: 2, max: 5, cpu: 80 },
76
+ },
77
+ {
78
+ name: 'worker',
79
+ replicas: isProduction ? 3 : 1,
80
+ port: 5000,
81
+ memory: '1Gi',
82
+ cpu: '1',
83
+ secrets: ['DATABASE_URL', 'REDIS_URL', 'AWS_ACCESS_KEY', 'AWS_SECRET_KEY'],
84
+ // No autoscale for workers
85
+ },
86
+ ];
87
+
88
+ // Cron jobs
89
+ const cronJobs = [
90
+ { name: 'cleanup', schedule: '0 3 * * *', command: ['node', 'scripts/cleanup.js'] },
91
+ { name: 'reports', schedule: '0 8 * * 1', command: ['node', 'scripts/weekly-report.js'] },
92
+ { name: 'backups', schedule: '0 2 * * *', command: ['node', 'scripts/backup.js'] },
93
+ ];
94
+
95
+ // ============================================================================
96
+ // Reusable Components
97
+ // ============================================================================
98
+
99
+ interface StandardContainerProps {
100
+ name: string;
101
+ port: number;
102
+ memory: string;
103
+ cpu: string;
104
+ secrets: string[];
105
+ }
106
+
107
+ const StandardContainer = ({ name, port, memory, cpu, secrets }: StandardContainerProps) => (
108
+ <Container name={name} image={`mycompany/${name}:${VERSION}`}>
109
+ <Port container={port} />
110
+
111
+ {/* Common env vars */}
112
+ <Env name="NODE_ENV" value={ENV} />
113
+ <Env name="SERVICE_NAME" value={name} />
114
+ <Env name="LOG_LEVEL">
115
+ <ConfigMapRef name="app-config" key="log_level" />
116
+ </Env>
117
+
118
+ {/* Service-specific secrets */}
119
+ {secrets.map(secret => (
120
+ <Env key={secret} name={secret}>
121
+ <SecretRef name="app-secrets" secretKey={secret.toLowerCase().replace(/_/g, '-')} />
122
+ </Env>
123
+ ))}
124
+
125
+ <Resources
126
+ requestMemory={memory}
127
+ requestCpu={cpu}
128
+ limitMemory={memory}
129
+ limitCpu={cpu}
130
+ />
131
+
132
+ <Probe type="liveness" delay={30} period={10}>
133
+ <HttpProbe path="/health" port={port} />
134
+ </Probe>
135
+ <Probe type="readiness" delay={5} period={5}>
136
+ <HttpProbe path="/ready" port={port} />
137
+ </Probe>
138
+
139
+ {/* Temp storage for logs */}
140
+ <VolumeMount name="tmp" mountPath="/tmp" />
141
+ </Container>
142
+ );
143
+
144
+ // ============================================================================
145
+ // Main Infrastructure
146
+ // ============================================================================
147
+
148
+ const ProductionStack = () => (
149
+ <Cluster name="production">
150
+ {/* ================================================================== */}
151
+ {/* Backend Namespace */}
152
+ {/* ================================================================== */}
153
+ <Namespace name="backend" labels={{ team: 'platform', env: ENV }}>
154
+
155
+ {/* Shared ConfigMap */}
156
+ <ConfigMap
157
+ name="app-config"
158
+ data={{
159
+ log_level: isProduction ? 'info' : 'debug',
160
+ feature_flags: JSON.stringify({ newUI: true, analytics: isProduction }),
161
+ }}
162
+ />
163
+
164
+ {/* Shared Secret (in practice, use external secrets manager) */}
165
+ <Secret
166
+ name="app-secrets"
167
+ stringData={{
168
+ 'database-url': '${DATABASE_URL}',
169
+ 'redis-url': '${REDIS_URL}',
170
+ 'jwt-secret': '${JWT_SECRET}',
171
+ 'oauth-client-secret': '${OAUTH_CLIENT_SECRET}',
172
+ 'aws-access-key': '${AWS_ACCESS_KEY}',
173
+ 'aws-secret-key': '${AWS_SECRET_KEY}',
174
+ }}
175
+ />
176
+
177
+ {/* Service Account with RBAC */}
178
+ <ServiceAccount name="backend-sa" />
179
+ <Role
180
+ name="backend-role"
181
+ rules={[
182
+ { apiGroups: [''], resources: ['configmaps', 'secrets'], verbs: ['get', 'list', 'watch'] },
183
+ { apiGroups: [''], resources: ['pods'], verbs: ['get', 'list'] },
184
+ ]}
185
+ />
186
+ <RoleBinding
187
+ name="backend-role-binding"
188
+ roleRef={{ kind: 'Role', name: 'backend-role' }}
189
+ subjects={[{ kind: 'ServiceAccount', name: 'backend-sa' }]}
190
+ />
191
+
192
+ {/* Deploy all services using loop! */}
193
+ {services.map(svc => (
194
+ <Manifest key={svc.name}>
195
+ <Deployment
196
+ name={svc.name}
197
+ replicas={svc.replicas}
198
+ labels={{ app: svc.name, version: VERSION }}
199
+ >
200
+ <StandardContainer
201
+ name={svc.name}
202
+ port={svc.port}
203
+ memory={svc.memory}
204
+ cpu={svc.cpu}
205
+ secrets={svc.secrets}
206
+ />
207
+ <Volume name="tmp">
208
+ <EmptyDir />
209
+ </Volume>
210
+ </Deployment>
211
+
212
+ <Service
213
+ name={svc.name}
214
+ port={80}
215
+ targetPort={svc.port}
216
+ selector={{ app: svc.name }}
217
+ />
218
+
219
+ {/* HPA only for services with autoscale config */}
220
+ {svc.autoscale && (
221
+ <Hpa
222
+ name={`${svc.name}-hpa`}
223
+ target={svc.name}
224
+ minReplicas={svc.autoscale.min}
225
+ maxReplicas={svc.autoscale.max}
226
+ targetCpuUtilization={svc.autoscale.cpu}
227
+ />
228
+ )}
229
+ </Manifest>
230
+ ))}
231
+
232
+ {/* Ingress for public services */}
233
+ <Ingress name="backend-ingress" className="nginx" ssl>
234
+ {services
235
+ .filter(svc => svc.host)
236
+ .map(svc => (
237
+ <IngressHost key={svc.name} host={svc.host!}>
238
+ <Route path="/" service={svc.name} port={80} />
239
+ </IngressHost>
240
+ ))
241
+ }
242
+ </Ingress>
243
+
244
+ {/* Cron Jobs */}
245
+ {cronJobs.map(job => (
246
+ <CronJob
247
+ key={job.name}
248
+ name={job.name}
249
+ schedule={job.schedule}
250
+ concurrencyPolicy="Forbid"
251
+ >
252
+ <Container
253
+ name={job.name}
254
+ image={`mycompany/jobs:${VERSION}`}
255
+ command={job.command}
256
+ >
257
+ <Env name="DATABASE_URL">
258
+ <SecretRef name="app-secrets" secretKey="database-url" />
259
+ </Env>
260
+ <Resources requestMemory="256Mi" requestCpu="100m" />
261
+ </Container>
262
+ </CronJob>
263
+ ))}
264
+ </Namespace>
265
+
266
+ {/* ================================================================== */}
267
+ {/* Database Namespace */}
268
+ {/* ================================================================== */}
269
+ <Namespace name="databases" labels={{ team: 'platform', env: ENV }}>
270
+
271
+ {/* PostgreSQL PVC */}
272
+ <Pvc
273
+ name="postgres-data"
274
+ storage="100Gi"
275
+ accessModes={['ReadWriteOnce']}
276
+ storageClassName="ssd"
277
+ />
278
+
279
+ {/* PostgreSQL Deployment */}
280
+ <Deployment name="postgres" replicas={1}>
281
+ <Container name="postgres" image="postgres:15-alpine">
282
+ <Port container={5432} />
283
+ <Env name="POSTGRES_PASSWORD">
284
+ <SecretRef name="postgres-secrets" key="password" />
285
+ </Env>
286
+ <Env name="POSTGRES_DB" value="myapp" />
287
+ <Resources
288
+ requestMemory="1Gi"
289
+ requestCpu="500m"
290
+ limitMemory="2Gi"
291
+ limitCpu="1"
292
+ />
293
+ <Probe type="readiness" delay={5} period={10}>
294
+ <ExecProbe command={['pg_isready', '-U', 'postgres']} />
295
+ </Probe>
296
+ <VolumeMount name="data" mountPath="/var/lib/postgresql/data" />
297
+ </Container>
298
+ <Volume name="data">
299
+ <PvcVolume claimName="postgres-data" />
300
+ </Volume>
301
+ </Deployment>
302
+
303
+ <Service name="postgres" port={5432} targetPort={5432} type="ClusterIP" />
304
+
305
+ {/* Redis Deployment */}
306
+ <Deployment name="redis" replicas={1}>
307
+ <Container name="redis" image="redis:7-alpine">
308
+ <Port container={6379} />
309
+ <Resources
310
+ requestMemory="256Mi"
311
+ requestCpu="100m"
312
+ limitMemory="512Mi"
313
+ limitCpu="200m"
314
+ />
315
+ <Probe type="readiness" delay={5}>
316
+ <ExecProbe command={['redis-cli', 'ping']} />
317
+ </Probe>
318
+ </Container>
319
+ </Deployment>
320
+
321
+ <Service name="redis" port={6379} targetPort={6379} type="ClusterIP" />
322
+
323
+ </Namespace>
324
+ </Cluster>
325
+ );
326
+
327
+ // ============================================================================
328
+ // Render Output
329
+ // ============================================================================
330
+
331
+ console.log('🎯 Kubetsx - Generating Kubernetes manifests...\n');
332
+ console.log(`Environment: ${ENV}`);
333
+ console.log(`Version: ${VERSION}`);
334
+ console.log(`Services: ${services.map(s => s.name).join(', ')}`);
335
+ console.log(`Cron Jobs: ${cronJobs.map(j => j.name).join(', ')}`);
336
+ console.log('\n---\n');
337
+
338
+ render(<ProductionStack />);
339
+
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "jsx": "react-jsx",
12
+ "jsxImportSource": "../dist",
13
+ "paths": {
14
+ "kubetsx": ["../dist/index.js"],
15
+ "kubetsx/*": ["../dist/*"]
16
+ },
17
+ "baseUrl": "."
18
+ },
19
+ "include": ["./**/*"]
20
+ }
21
+
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "kubetsx",
3
+ "version": "0.1.0",
4
+ "description": "The Declarative Kubernetes Framework. Write K8s configs with JSX. Yes, really.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./jsx-runtime": {
14
+ "types": "./dist/jsx-runtime.d.ts",
15
+ "import": "./dist/jsx-runtime.js"
16
+ }
17
+ },
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "dev": "tsc --watch",
21
+ "example": "npm run build && node --experimental-strip-types examples/full-stack.tsx",
22
+ "example:basic": "npm run build && node --experimental-strip-types examples/basic.tsx",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "kubernetes",
27
+ "k8s",
28
+ "jsx",
29
+ "tsx",
30
+ "yaml",
31
+ "declarative",
32
+ "infrastructure",
33
+ "config",
34
+ "devops"
35
+ ],
36
+ "author": "malekabdelkader",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/malekabdelkader/kubetsx.git"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/malekabdelkader/kubetsx/issues"
44
+ },
45
+ "homepage": "https://github.com/malekabdelkader/kubetsx#readme",
46
+ "devDependencies": {
47
+ "@types/node": "^22.0.0",
48
+ "typescript": "^5.7.0"
49
+ },
50
+ "dependencies": {
51
+ "yaml": "^2.7.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=22.0.0"
55
+ }
56
+ }
57
+
@@ -0,0 +1,241 @@
1
+ /**
2
+ * 🎯 Kubetsx - Component Definitions
3
+ *
4
+ * All Kubernetes resource components as JSX elements
5
+ */
6
+
7
+ import { h } from '../jsx-runtime.js';
8
+ import type {
9
+ KubexElement,
10
+ KubexNode,
11
+ ManifestProps,
12
+ ClusterProps,
13
+ NamespaceProps,
14
+ DeploymentProps,
15
+ ContainerProps,
16
+ PortProps,
17
+ EnvProps,
18
+ SecretRefProps,
19
+ ConfigMapRefProps,
20
+ ResourcesProps,
21
+ ProbeProps,
22
+ HttpProbeProps,
23
+ TcpProbeProps,
24
+ ExecProbeProps,
25
+ ServiceProps,
26
+ IngressProps,
27
+ IngressHostProps,
28
+ RouteProps,
29
+ ConfigMapProps,
30
+ SecretProps,
31
+ VolumeProps,
32
+ VolumeMountProps,
33
+ EmptyDirProps,
34
+ PvcVolumeProps,
35
+ ConfigMapVolumeProps,
36
+ SecretVolumeProps,
37
+ PvcProps,
38
+ HpaProps,
39
+ JobProps,
40
+ CronJobProps,
41
+ ServiceAccountProps,
42
+ RoleProps,
43
+ ClusterRoleProps,
44
+ RoleBindingProps,
45
+ ClusterRoleBindingProps,
46
+ } from '../types.js';
47
+
48
+ // Helper to get children array
49
+ function getChildren(children: KubexNode | undefined): KubexNode[] {
50
+ if (!children) return [];
51
+ return Array.isArray(children) ? children : [children];
52
+ }
53
+
54
+ // Cast helper
55
+ function toProps(props: object): Record<string, unknown> {
56
+ return props as Record<string, unknown>;
57
+ }
58
+
59
+ // ============================================================================
60
+ // Manifest (Fragment alternative - groups multiple resources)
61
+ // ============================================================================
62
+
63
+ export function Manifest(props: ManifestProps): KubexElement {
64
+ return h('Manifest', toProps(props), ...getChildren(props.children));
65
+ }
66
+
67
+ // ============================================================================
68
+ // Cluster & Namespace
69
+ // ============================================================================
70
+
71
+ export function Cluster(props: ClusterProps): KubexElement {
72
+ return h('Cluster', toProps(props), ...getChildren(props.children));
73
+ }
74
+
75
+ export function Namespace(props: NamespaceProps): KubexElement {
76
+ return h('Namespace', toProps(props), ...getChildren(props.children));
77
+ }
78
+
79
+ // ============================================================================
80
+ // Workloads
81
+ // ============================================================================
82
+
83
+ export function Deployment(props: DeploymentProps): KubexElement {
84
+ return h('Deployment', toProps(props), ...getChildren(props.children));
85
+ }
86
+
87
+ export function Container(props: ContainerProps & { children?: KubexNode }): KubexElement {
88
+ return h('Container', toProps(props), ...getChildren(props.children));
89
+ }
90
+
91
+ export function Job(props: JobProps): KubexElement {
92
+ return h('Job', toProps(props), ...getChildren(props.children));
93
+ }
94
+
95
+ export function CronJob(props: CronJobProps): KubexElement {
96
+ return h('CronJob', toProps(props), ...getChildren(props.children));
97
+ }
98
+
99
+ // ============================================================================
100
+ // Container Configuration
101
+ // ============================================================================
102
+
103
+ export function Port(props: PortProps): KubexElement {
104
+ return h('Port', toProps(props));
105
+ }
106
+
107
+ export function Env(props: EnvProps): KubexElement {
108
+ return h('Env', toProps(props), ...getChildren(props.children));
109
+ }
110
+
111
+ export function SecretRef(props: SecretRefProps): KubexElement {
112
+ return h('SecretRef', toProps(props));
113
+ }
114
+
115
+ export function ConfigMapRef(props: ConfigMapRefProps): KubexElement {
116
+ return h('ConfigMapRef', toProps(props));
117
+ }
118
+
119
+ export function Resources(props: ResourcesProps): KubexElement {
120
+ return h('Resources', toProps(props));
121
+ }
122
+
123
+ // ============================================================================
124
+ // Probes
125
+ // ============================================================================
126
+
127
+ export function Probe(props: ProbeProps): KubexElement {
128
+ return h('Probe', toProps(props), ...getChildren(props.children));
129
+ }
130
+
131
+ export function HttpProbe(props: HttpProbeProps): KubexElement {
132
+ return h('HttpProbe', toProps(props));
133
+ }
134
+
135
+ export function TcpProbe(props: TcpProbeProps): KubexElement {
136
+ return h('TcpProbe', toProps(props));
137
+ }
138
+
139
+ export function ExecProbe(props: ExecProbeProps): KubexElement {
140
+ return h('ExecProbe', toProps(props));
141
+ }
142
+
143
+ // ============================================================================
144
+ // Networking
145
+ // ============================================================================
146
+
147
+ export function Service(props: ServiceProps): KubexElement {
148
+ return h('Service', toProps(props));
149
+ }
150
+
151
+ export function Ingress(props: IngressProps & { host?: string }): KubexElement {
152
+ return h('Ingress', toProps(props), ...getChildren(props.children));
153
+ }
154
+
155
+ export function IngressHost(props: IngressHostProps): KubexElement {
156
+ return h('IngressHost', toProps(props), ...getChildren(props.children));
157
+ }
158
+
159
+ export function Route(props: RouteProps): KubexElement {
160
+ return h('Route', toProps(props));
161
+ }
162
+
163
+ // ============================================================================
164
+ // Configuration
165
+ // ============================================================================
166
+
167
+ export function ConfigMap(props: ConfigMapProps): KubexElement {
168
+ return h('ConfigMap', toProps(props));
169
+ }
170
+
171
+ export function Secret(props: SecretProps): KubexElement {
172
+ return h('Secret', toProps(props));
173
+ }
174
+
175
+ // ============================================================================
176
+ // Volumes
177
+ // ============================================================================
178
+
179
+ export function Volume(props: VolumeProps): KubexElement {
180
+ return h('Volume', toProps(props), ...getChildren(props.children));
181
+ }
182
+
183
+ export function VolumeMount(props: VolumeMountProps): KubexElement {
184
+ return h('VolumeMount', toProps(props));
185
+ }
186
+
187
+ export function EmptyDir(props: EmptyDirProps = {}): KubexElement {
188
+ return h('EmptyDir', toProps(props));
189
+ }
190
+
191
+ export function PvcVolume(props: PvcVolumeProps): KubexElement {
192
+ return h('PvcVolume', toProps(props));
193
+ }
194
+
195
+ export function ConfigMapVolume(props: ConfigMapVolumeProps): KubexElement {
196
+ return h('ConfigMapVolume', toProps(props));
197
+ }
198
+
199
+ export function SecretVolume(props: SecretVolumeProps): KubexElement {
200
+ return h('SecretVolume', toProps(props));
201
+ }
202
+
203
+ // ============================================================================
204
+ // Storage
205
+ // ============================================================================
206
+
207
+ export function Pvc(props: PvcProps): KubexElement {
208
+ return h('Pvc', toProps(props));
209
+ }
210
+
211
+ // ============================================================================
212
+ // Autoscaling
213
+ // ============================================================================
214
+
215
+ export function Hpa(props: HpaProps): KubexElement {
216
+ return h('Hpa', toProps(props));
217
+ }
218
+
219
+ // ============================================================================
220
+ // RBAC & Service Accounts
221
+ // ============================================================================
222
+
223
+ export function ServiceAccount(props: ServiceAccountProps): KubexElement {
224
+ return h('ServiceAccount', toProps(props));
225
+ }
226
+
227
+ export function Role(props: RoleProps): KubexElement {
228
+ return h('Role', toProps(props));
229
+ }
230
+
231
+ export function ClusterRole(props: ClusterRoleProps): KubexElement {
232
+ return h('ClusterRole', toProps(props));
233
+ }
234
+
235
+ export function RoleBinding(props: RoleBindingProps): KubexElement {
236
+ return h('RoleBinding', toProps(props));
237
+ }
238
+
239
+ export function ClusterRoleBinding(props: ClusterRoleBindingProps): KubexElement {
240
+ return h('ClusterRoleBinding', toProps(props));
241
+ }