@vibesdotdev/infra-core 0.0.1

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 (133) hide show
  1. package/README.md +78 -0
  2. package/SPEC.md +169 -0
  3. package/dist/bootstrap/index.d.ts +5 -0
  4. package/dist/bootstrap/index.d.ts.map +1 -0
  5. package/dist/bootstrap/index.js +4 -0
  6. package/dist/bootstrap/index.js.map +1 -0
  7. package/dist/bootstrap/seed.descriptor.d.ts +31 -0
  8. package/dist/bootstrap/seed.descriptor.d.ts.map +1 -0
  9. package/dist/bootstrap/seed.descriptor.js +18 -0
  10. package/dist/bootstrap/seed.descriptor.js.map +1 -0
  11. package/dist/bootstrap/seed.impl-shape.d.ts +5 -0
  12. package/dist/bootstrap/seed.impl-shape.d.ts.map +1 -0
  13. package/dist/bootstrap/seed.impl-shape.js +2 -0
  14. package/dist/bootstrap/seed.impl-shape.js.map +1 -0
  15. package/dist/bootstrap/seed.kind.d.ts +5 -0
  16. package/dist/bootstrap/seed.kind.d.ts.map +1 -0
  17. package/dist/bootstrap/seed.kind.js +14 -0
  18. package/dist/bootstrap/seed.kind.js.map +1 -0
  19. package/dist/bootstrap/seed.runner.d.ts +18 -0
  20. package/dist/bootstrap/seed.runner.d.ts.map +1 -0
  21. package/dist/bootstrap/seed.runner.js +59 -0
  22. package/dist/bootstrap/seed.runner.js.map +1 -0
  23. package/dist/credentials/resolve.d.ts +80 -0
  24. package/dist/credentials/resolve.d.ts.map +1 -0
  25. package/dist/credentials/resolve.js +128 -0
  26. package/dist/credentials/resolve.js.map +1 -0
  27. package/dist/deployment.d.ts +9 -0
  28. package/dist/deployment.d.ts.map +1 -0
  29. package/dist/deployment.js +25 -0
  30. package/dist/deployment.js.map +1 -0
  31. package/dist/index.d.ts +32 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +21 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/infra.plugin.d.ts +18 -0
  36. package/dist/infra.plugin.d.ts.map +1 -0
  37. package/dist/infra.plugin.js +52 -0
  38. package/dist/infra.plugin.js.map +1 -0
  39. package/dist/kinds/alerts.kind.d.ts +192 -0
  40. package/dist/kinds/alerts.kind.d.ts.map +1 -0
  41. package/dist/kinds/alerts.kind.js +116 -0
  42. package/dist/kinds/alerts.kind.js.map +1 -0
  43. package/dist/kinds/artifact.kind.d.ts +96 -0
  44. package/dist/kinds/artifact.kind.d.ts.map +1 -0
  45. package/dist/kinds/artifact.kind.js +53 -0
  46. package/dist/kinds/artifact.kind.js.map +1 -0
  47. package/dist/kinds/cache.kind.d.ts +128 -0
  48. package/dist/kinds/cache.kind.d.ts.map +1 -0
  49. package/dist/kinds/cache.kind.js +90 -0
  50. package/dist/kinds/cache.kind.js.map +1 -0
  51. package/dist/kinds/database.kind.d.ts +141 -0
  52. package/dist/kinds/database.kind.d.ts.map +1 -0
  53. package/dist/kinds/database.kind.js +103 -0
  54. package/dist/kinds/database.kind.js.map +1 -0
  55. package/dist/kinds/discovery.d.ts +20 -0
  56. package/dist/kinds/discovery.d.ts.map +1 -0
  57. package/dist/kinds/discovery.js +25 -0
  58. package/dist/kinds/discovery.js.map +1 -0
  59. package/dist/kinds/git-hosting.kind.d.ts +98 -0
  60. package/dist/kinds/git-hosting.kind.d.ts.map +1 -0
  61. package/dist/kinds/git-hosting.kind.js +81 -0
  62. package/dist/kinds/git-hosting.kind.js.map +1 -0
  63. package/dist/kinds/index.d.ts +16 -0
  64. package/dist/kinds/index.d.ts.map +1 -0
  65. package/dist/kinds/index.js +16 -0
  66. package/dist/kinds/index.js.map +1 -0
  67. package/dist/kinds/logs.kind.d.ts +91 -0
  68. package/dist/kinds/logs.kind.d.ts.map +1 -0
  69. package/dist/kinds/logs.kind.js +73 -0
  70. package/dist/kinds/logs.kind.js.map +1 -0
  71. package/dist/kinds/object-storage.kind.d.ts +85 -0
  72. package/dist/kinds/object-storage.kind.d.ts.map +1 -0
  73. package/dist/kinds/object-storage.kind.js +81 -0
  74. package/dist/kinds/object-storage.kind.js.map +1 -0
  75. package/dist/kinds/observability.kind.d.ts +176 -0
  76. package/dist/kinds/observability.kind.d.ts.map +1 -0
  77. package/dist/kinds/observability.kind.js +120 -0
  78. package/dist/kinds/observability.kind.js.map +1 -0
  79. package/dist/kinds/package-registry.kind.d.ts +89 -0
  80. package/dist/kinds/package-registry.kind.d.ts.map +1 -0
  81. package/dist/kinds/package-registry.kind.js +78 -0
  82. package/dist/kinds/package-registry.kind.js.map +1 -0
  83. package/dist/kinds/queue.kind.d.ts +113 -0
  84. package/dist/kinds/queue.kind.d.ts.map +1 -0
  85. package/dist/kinds/queue.kind.js +86 -0
  86. package/dist/kinds/queue.kind.js.map +1 -0
  87. package/dist/kinds/rum.kind.d.ts +113 -0
  88. package/dist/kinds/rum.kind.d.ts.map +1 -0
  89. package/dist/kinds/rum.kind.js +80 -0
  90. package/dist/kinds/rum.kind.js.map +1 -0
  91. package/dist/kinds/sandbox.kind.d.ts +111 -0
  92. package/dist/kinds/sandbox.kind.d.ts.map +1 -0
  93. package/dist/kinds/sandbox.kind.js +94 -0
  94. package/dist/kinds/sandbox.kind.js.map +1 -0
  95. package/dist/kinds/web-app.kind.d.ts +99 -0
  96. package/dist/kinds/web-app.kind.d.ts.map +1 -0
  97. package/dist/kinds/web-app.kind.js +86 -0
  98. package/dist/kinds/web-app.kind.js.map +1 -0
  99. package/dist/kinds/worker.kind.d.ts +244 -0
  100. package/dist/kinds/worker.kind.d.ts.map +1 -0
  101. package/dist/kinds/worker.kind.js +171 -0
  102. package/dist/kinds/worker.kind.js.map +1 -0
  103. package/dist/schemas.d.ts +125 -0
  104. package/dist/schemas.d.ts.map +1 -0
  105. package/dist/schemas.js +102 -0
  106. package/dist/schemas.js.map +1 -0
  107. package/package.json +92 -0
  108. package/src/bootstrap/index.ts +15 -0
  109. package/src/bootstrap/seed.descriptor.ts +24 -0
  110. package/src/bootstrap/seed.impl-shape.ts +5 -0
  111. package/src/bootstrap/seed.kind.ts +26 -0
  112. package/src/bootstrap/seed.runner.ts +87 -0
  113. package/src/credentials/resolve.ts +205 -0
  114. package/src/deployment.ts +57 -0
  115. package/src/index.ts +149 -0
  116. package/src/infra.plugin.ts +54 -0
  117. package/src/kinds/alerts.kind.ts +164 -0
  118. package/src/kinds/artifact.kind.ts +96 -0
  119. package/src/kinds/cache.kind.ts +104 -0
  120. package/src/kinds/database.kind.ts +120 -0
  121. package/src/kinds/discovery.ts +26 -0
  122. package/src/kinds/git-hosting.kind.ts +100 -0
  123. package/src/kinds/index.ts +139 -0
  124. package/src/kinds/logs.kind.ts +104 -0
  125. package/src/kinds/object-storage.kind.ts +101 -0
  126. package/src/kinds/observability.kind.ts +178 -0
  127. package/src/kinds/package-registry.kind.ts +95 -0
  128. package/src/kinds/queue.kind.ts +102 -0
  129. package/src/kinds/rum.kind.ts +135 -0
  130. package/src/kinds/sandbox.kind.ts +115 -0
  131. package/src/kinds/web-app.kind.ts +103 -0
  132. package/src/kinds/worker.kind.ts +203 -0
  133. package/src/schemas.ts +127 -0
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Kind: infra/object-storage
3
+ *
4
+ * Describes object/blob storage.
5
+ *
6
+ * Schema shape: strict common base + `config` discriminated union.
7
+ *
8
+ * - The base defines fields universal across adapters: id/kind/name +
9
+ * the storage shape (bucket, cors, lifecycle, publicAccess).
10
+ * - Adapter-specific fields (region, acl, …) live under `config`.
11
+ * Each adapter package defines its own concrete schema.
12
+ */
13
+ import * as z from 'zod/v4';
14
+ import { createRuntimeKind } from '@vibesdotdev/runtime/factory/kind';
15
+ import type { RuntimeKindDescriptorRecord } from '@vibesdotdev/runtime/schemas/kind';
16
+ import { RuntimeDescriptorSchema } from '@vibesdotdev/runtime/schemas/descriptor';
17
+ import type { RuntimeDescriptor } from '@vibesdotdev/runtime/schemas/descriptor';
18
+ import { INFRA_DISCOVERY_PATTERN, extractStem } from './discovery.ts';
19
+
20
+ export const CorsRuleSchema = z.object({
21
+ allowedOrigins: z.array(z.string()).default(['*']),
22
+ allowedMethods: z.array(z.string()).default(['GET']),
23
+ allowedHeaders: z.array(z.string()).optional(),
24
+ maxAgeSeconds: z.number().int().nonnegative().optional()
25
+ });
26
+ export type CorsRule = z.infer<typeof CorsRuleSchema>;
27
+
28
+ export const LifecycleRuleSchema = z.object({
29
+ /** Prefix filter for matching objects */
30
+ prefix: z.string().optional(),
31
+ /** Days until expiration */
32
+ expiration: z.number().int().positive().optional(),
33
+ /** Storage class transition */
34
+ transition: z
35
+ .object({
36
+ days: z.number().int().positive(),
37
+ storageClass: z.string().min(1)
38
+ })
39
+ .optional()
40
+ });
41
+ export type LifecycleRule = z.infer<typeof LifecycleRuleSchema>;
42
+
43
+ const ObjectStorageBaseSchema = RuntimeDescriptorSchema.extend({
44
+ kind: z.literal('infra/object-storage'),
45
+
46
+ /** Bucket name (defaults to descriptor id when omitted). */
47
+ bucket: z.string().min(1).optional(),
48
+
49
+ /** CORS rules. */
50
+ cors: z.array(CorsRuleSchema).optional(),
51
+
52
+ /** Lifecycle rules. */
53
+ lifecycle: z.array(LifecycleRuleSchema).optional(),
54
+
55
+ /** Whether the bucket is publicly readable. */
56
+ publicAccess: z.boolean().optional()
57
+ });
58
+
59
+ export const DOSpacesConfigSchema = z.object({
60
+ /** DO region (default: nyc3). */
61
+ region: z.string().min(1).default('nyc3')
62
+ });
63
+
64
+ export const CloudflareR2ConfigSchema = z.object({});
65
+
66
+ export const ObjectStorageConfigSchema = z.union([
67
+ DOSpacesConfigSchema.extend({ adapter: z.literal('do-spaces') }),
68
+ CloudflareR2ConfigSchema.extend({ adapter: z.literal('cloudflare-r2') })
69
+ ]);
70
+
71
+ export const ObjectStorageDescriptorSchema = ObjectStorageBaseSchema.extend({
72
+ /**
73
+ * Adapter-specific configuration. Discriminated union — each adapter
74
+ * package defines its own config schema under its discriminator key.
75
+ */
76
+ config: ObjectStorageConfigSchema.optional()
77
+ });
78
+
79
+ export type ObjectStorageDescriptor = z.infer<typeof ObjectStorageDescriptorSchema>;
80
+
81
+ class DefaultObjectStorageImplementation {
82
+ constructor(
83
+ public readonly descriptor: RuntimeDescriptor,
84
+ public readonly context: unknown
85
+ ) {}
86
+
87
+ get config(): ObjectStorageDescriptor {
88
+ return this.descriptor as ObjectStorageDescriptor;
89
+ }
90
+ }
91
+
92
+ export const objectStorageKind = createRuntimeKind<
93
+ ObjectStorageDescriptor,
94
+ DefaultObjectStorageImplementation
95
+ >({
96
+ id: 'infra/object-storage',
97
+ descriptorSchema: ObjectStorageDescriptorSchema,
98
+ defaultImplementation: DefaultObjectStorageImplementation,
99
+ discoveryPattern: INFRA_DISCOVERY_PATTERN,
100
+ extractStem
101
+ });
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Infra Observability Kind
3
+ *
4
+ * Provider-agnostic per-Worker (or fleet-wide) observability config —
5
+ * sampling rate, log/trace toggles, export destinations. Decouples
6
+ * observability concerns from the `infra/web-app` descriptor so:
7
+ *
8
+ * 1. The CLI can introspect + write settings across the entire fleet
9
+ * without going through deploy.
10
+ * 2. Cross-cutting policies (e.g. "10% sampling on every customer-facing
11
+ * Worker") have a single declarative shape.
12
+ * 3. Provider impls map onto the native control plane (CF Workers
13
+ * Observability, DO Monitoring, Datadog, etc.).
14
+ *
15
+ * CLI surface (`vibes infra observability …`):
16
+ * status [--worker] read current settings
17
+ * set [--worker] --sampling 0.1 write new settings
18
+ * exports list|add|remove (Phase 2.5; not yet wired)
19
+ *
20
+ * Production Workers consume settings via their wrangler.jsonc; the CLI
21
+ * writes directly to the provider API for immediate effect. To avoid
22
+ * drift, `vibes infra deploy regenerate` is the canonical declarative
23
+ * path — the CLI here is for ops-time tuning between deploys.
24
+ */
25
+
26
+ import * as z from 'zod/v4';
27
+ import { createRuntimeKind } from '@vibesdotdev/runtime/factory/kind';
28
+ import { RuntimeDescriptorSchema } from '@vibesdotdev/runtime/schemas/descriptor';
29
+ import { INFRA_DISCOVERY_PATTERN, extractStem } from './discovery.ts';
30
+
31
+ const ObservabilityScopeSchema = z.discriminatedUnion('kind', [
32
+ z.object({
33
+ kind: z.literal('worker'),
34
+ workerName: z.string().min(1)
35
+ }),
36
+ z.object({
37
+ kind: z.literal('account-wide'),
38
+ /** When set, restrict the fleet sweep to workers matching the glob. */
39
+ filter: z.string().optional()
40
+ })
41
+ ]);
42
+
43
+ export type ObservabilityScope = z.infer<typeof ObservabilityScopeSchema>;
44
+
45
+ /**
46
+ * Standard observability settings shape. Provider impls translate
47
+ * these onto native fields (CF: `observability.head_sampling_rate`,
48
+ * Datadog: `apm_sampling_rate`, etc.).
49
+ */
50
+ const ObservabilitySettingsSchema = z.object({
51
+ logs: z
52
+ .object({
53
+ enabled: z.boolean(),
54
+ /**
55
+ * Head sampling rate, 0..1. Providers without head-sampling
56
+ * (e.g. Logpush-only setups) treat this as a hint and may
57
+ * implement tail-sampling at the destination instead.
58
+ */
59
+ headSamplingRate: z.number().min(0).max(1).optional(),
60
+ structured: z.boolean().optional(),
61
+ /** Persist logs for dashboard view (CF: observability.logs.persist). */
62
+ persist: z.boolean().optional(),
63
+ /** Capture per-request invocation envelopes (CF only). */
64
+ invocationLogs: z.boolean().optional()
65
+ })
66
+ .optional(),
67
+ traces: z
68
+ .object({
69
+ enabled: z.boolean(),
70
+ headSamplingRate: z.number().min(0).max(1).optional(),
71
+ persist: z.boolean().optional(),
72
+ exporter: z
73
+ .object({
74
+ kind: z.enum(['otlp', 'datadog', 'jaeger']),
75
+ endpoint: z.string().url(),
76
+ tokenSecretKey: z.string().optional()
77
+ })
78
+ .optional()
79
+ })
80
+ .optional(),
81
+ exports: z
82
+ .array(
83
+ z.discriminatedUnion('kind', [
84
+ z.object({
85
+ kind: z.literal('logflare'),
86
+ tokenSecretKey: z.string()
87
+ }),
88
+ z.object({
89
+ kind: z.literal('datadog'),
90
+ apiKeySecretKey: z.string(),
91
+ site: z.string()
92
+ }),
93
+ z.object({
94
+ kind: z.literal('logpush'),
95
+ destination: z.string(),
96
+ dataset: z.string()
97
+ })
98
+ ])
99
+ )
100
+ .optional()
101
+ });
102
+
103
+ export type ObservabilitySettings = z.infer<typeof ObservabilitySettingsSchema>;
104
+
105
+ const ObservabilityBaseSchema = RuntimeDescriptorSchema.extend({
106
+ kind: z.literal('infra/observability'),
107
+ adapter: z.string().min(1),
108
+ adapterConfig: z.record(z.string(), z.unknown()).optional(),
109
+ environment: z.string().default('local'),
110
+ /**
111
+ * Default scope when the descriptor is used standalone (e.g.
112
+ * `vibes infra observability status` with no --worker flag). When
113
+ * the CLI passes an explicit scope, this is ignored.
114
+ */
115
+ defaultScope: ObservabilityScopeSchema.default({ kind: 'account-wide' }),
116
+ /**
117
+ * Optional declared settings — used by `vibes infra observability
118
+ * sync` (future) to drive a desired-state reconciliation. Today the
119
+ * CLI imperatively sets values per call.
120
+ */
121
+ settings: ObservabilitySettingsSchema.optional()
122
+ });
123
+
124
+ export type InfraObservabilityDescriptor = z.infer<typeof ObservabilityBaseSchema>;
125
+ export type InfraObservabilityDescriptorInput = z.input<typeof ObservabilityBaseSchema>;
126
+
127
+ /**
128
+ * Snapshot of the live settings for a single Worker (or other scope).
129
+ * Returned by `getStatus`; consumed by the CLI for table-rendering.
130
+ */
131
+ export interface ObservabilitySnapshot {
132
+ workerName: string;
133
+ settings: ObservabilitySettings;
134
+ /** Last-modified timestamp from the provider, when available. */
135
+ modifiedAt?: string;
136
+ }
137
+
138
+ export interface SetObservabilityInput {
139
+ scope: ObservabilityScope;
140
+ settings: ObservabilitySettings;
141
+ /** Skip Workers that already match desired state. Defaults to true. */
142
+ skipUnchanged?: boolean;
143
+ }
144
+
145
+ export interface SetObservabilityResult {
146
+ changed: Array<{ workerName: string; before: ObservabilitySettings; after: ObservabilitySettings }>;
147
+ unchanged: string[];
148
+ failed: Array<{ workerName: string; error: string }>;
149
+ }
150
+
151
+ /**
152
+ * Implementation contract every provider implements.
153
+ */
154
+ export interface ObservabilityImplementation {
155
+ /** Read current settings for a scope. account-wide → one snapshot per Worker. */
156
+ getStatus(scope: ObservabilityScope): Promise<ObservabilitySnapshot[]>;
157
+ /** Apply settings to a scope. Returns per-Worker outcome. */
158
+ set(input: SetObservabilityInput): Promise<SetObservabilityResult>;
159
+ }
160
+
161
+ export const observabilityKind = createRuntimeKind<
162
+ InfraObservabilityDescriptor,
163
+ ObservabilityImplementation
164
+ >({
165
+ id: 'infra/observability',
166
+ descriptorSchema: ObservabilityBaseSchema,
167
+ discoveryPattern: INFRA_DISCOVERY_PATTERN,
168
+ extractStem
169
+ });
170
+
171
+ export type InfraObservabilityKind = InfraObservabilityDescriptor;
172
+ export type InfraObservabilityKindInput = InfraObservabilityDescriptorInput;
173
+
174
+ export {
175
+ ObservabilityBaseSchema as InfraObservabilityDescriptorSchema,
176
+ ObservabilityScopeSchema,
177
+ ObservabilitySettingsSchema
178
+ };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Kind: infra/package-registry
3
+ *
4
+ * Describes a package registry instance (npm, Docker, Maven, Helm, etc.).
5
+ *
6
+ * Schema shape: strict common base + `config` discriminated union.
7
+ *
8
+ * - The base (this file) defines fields that are universal across every
9
+ * adapter: id/kind/name + the registry shape every package host declares
10
+ * (url, registryType, scope, upstreamUrl, authRequired, ssl, env).
11
+ * - Adapter-specific fields (dockerImage, storageSize, domain, …)
12
+ * live exclusively under `config`. Each adapter package defines its own
13
+ * concrete schema under its discriminator key.
14
+ */
15
+ import * as z from 'zod/v4';
16
+ import { createRuntimeKind } from '@vibesdotdev/runtime/factory/kind';
17
+ import type { RuntimeKindDescriptorRecord } from '@vibesdotdev/runtime/schemas/kind';
18
+ import { RuntimeDescriptorSchema } from '@vibesdotdev/runtime/schemas/descriptor';
19
+ import type { RuntimeDescriptor } from '@vibesdotdev/runtime/schemas/descriptor';
20
+ import { INFRA_DISCOVERY_PATTERN, extractStem } from './discovery.ts';
21
+ import { deploymentEnvRequirementSchema } from '../schemas.ts';
22
+
23
+ export const PackageRegistryTypeSchema = z.enum(['npm', 'docker', 'maven', 'helm']);
24
+ export type PackageRegistryType = z.infer<typeof PackageRegistryTypeSchema>;
25
+
26
+ const PackageRegistryBaseSchema = RuntimeDescriptorSchema.extend({
27
+ kind: z.literal('infra/package-registry'),
28
+
29
+ /** Primary access URL (e.g. 'https://packages.vibes.dev'). */
30
+ url: z.string().url(),
31
+
32
+ /** Package type this registry serves. */
33
+ registryType: PackageRegistryTypeSchema.default('npm'),
34
+
35
+ /** Npm scope this registry owns (e.g. '@vibesdotdev'). */
36
+ scope: z.string().optional(),
37
+
38
+ /** Upstream registry URL this registry proxies (optional). */
39
+ upstreamUrl: z.string().url().optional(),
40
+
41
+ /** Whether authentication is required to pull from this registry. */
42
+ authRequired: z.boolean().default(true),
43
+
44
+ /** Whether TLS is enabled. */
45
+ ssl: z.boolean().default(true),
46
+
47
+ /** Environment variable requirements. */
48
+ env: z.array(deploymentEnvRequirementSchema).optional()
49
+ });
50
+
51
+ export const VerdaccioDoksPackageRegistryConfigSchema = z.object({
52
+ /** Docker image for the Verdaccio container. */
53
+ dockerImage: z.string().default('verdaccio/verdaccio:5'),
54
+ /** Persistent storage size (e.g. '10Gi'). */
55
+ storageSize: z.string().default('10Gi'),
56
+ /** Primary domain for the registry. */
57
+ domain: z.string().min(1),
58
+ /** Upstream npm registry URL to proxy. */
59
+ upstreamNpmUrl: z.string().url().default('https://registry.npmjs.org'),
60
+ /** Whether built-in authentication is enabled. */
61
+ authEnabled: z.boolean().default(true)
62
+ });
63
+
64
+ export const PackageRegistryConfigSchema = z.union([
65
+ VerdaccioDoksPackageRegistryConfigSchema.extend({ adapter: z.literal('verdaccio-doks') })
66
+ ]);
67
+
68
+ export const PackageRegistryDescriptorSchema = PackageRegistryBaseSchema.extend({
69
+ /**
70
+ * Adapter-specific configuration. Discriminated union — each adapter
71
+ * package defines its own config schema under its discriminator key.
72
+ */
73
+ config: PackageRegistryConfigSchema.optional()
74
+ });
75
+
76
+ export type PackageRegistryDescriptor = z.infer<typeof PackageRegistryDescriptorSchema>;
77
+
78
+ class DefaultPackageRegistryImplementation {
79
+ constructor(
80
+ public readonly descriptor: RuntimeDescriptor,
81
+ public readonly context: unknown
82
+ ) {}
83
+
84
+ get config(): PackageRegistryDescriptor {
85
+ return this.descriptor as PackageRegistryDescriptor;
86
+ }
87
+ }
88
+
89
+ export const packageRegistryKind = createRuntimeKind<PackageRegistryDescriptor, DefaultPackageRegistryImplementation>({
90
+ id: 'infra/package-registry',
91
+ descriptorSchema: PackageRegistryDescriptorSchema,
92
+ defaultImplementation: DefaultPackageRegistryImplementation,
93
+ discoveryPattern: INFRA_DISCOVERY_PATTERN,
94
+ extractStem
95
+ });
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Kind: infra/queue
3
+ *
4
+ * Describes a message queue system.
5
+ *
6
+ * Schema shape: strict common base + `config` discriminated union.
7
+ *
8
+ * - The base defines fields universal across adapters: id/kind/name +
9
+ * the queue shape (engine, topics, maxBatchSize, maxRetries, deadLetterQueue).
10
+ * - Adapter-specific fields (namespace, storageSize, resources, …) live under
11
+ * `config`. Each adapter package defines its own concrete schema.
12
+ */
13
+ import * as z from 'zod/v4';
14
+ import { createRuntimeKind } from '@vibesdotdev/runtime/factory/kind';
15
+ import type { RuntimeKindDescriptorRecord } from '@vibesdotdev/runtime/schemas/kind';
16
+ import { RuntimeDescriptorSchema } from '@vibesdotdev/runtime/schemas/descriptor';
17
+ import type { RuntimeDescriptor } from '@vibesdotdev/runtime/schemas/descriptor';
18
+ import { INFRA_DISCOVERY_PATTERN, extractStem } from './discovery.ts';
19
+
20
+ export const QueueTopicSchema = z.object({
21
+ name: z.string().min(1),
22
+ partitions: z.number().int().positive().optional(),
23
+ retention: z.string().optional(),
24
+ replication: z.number().int().positive().optional()
25
+ });
26
+ export type QueueTopic = z.infer<typeof QueueTopicSchema>;
27
+
28
+ const QueueBaseSchema = RuntimeDescriptorSchema.extend({
29
+ kind: z.literal('infra/queue'),
30
+
31
+ /** Queue engine (e.g., 'cloudflare-queues', 'redpanda'). */
32
+ engine: z.string().min(1).optional(),
33
+
34
+ /** Topic / queue declarations. */
35
+ topics: z.array(QueueTopicSchema).optional(),
36
+
37
+ /** Maximum batch size. */
38
+ maxBatchSize: z.number().int().positive().optional(),
39
+
40
+ /** Maximum retry count. */
41
+ maxRetries: z.number().int().nonnegative().optional(),
42
+
43
+ /** Dead-letter queue id. */
44
+ deadLetterQueue: z.string().optional()
45
+ });
46
+
47
+ export const DoksQueueConfigSchema = z.object({
48
+ /** Kubernetes namespace (default: vibes). */
49
+ namespace: z.string().min(1).default('vibes'),
50
+ /** Storage size for data volume (default: 10Gi). */
51
+ storageSize: z.string().min(1).default('10Gi'),
52
+ /** Container resources. */
53
+ resources: z
54
+ .object({
55
+ requests: z.object({ cpu: z.string().min(1), memory: z.string().min(1) }).optional(),
56
+ limits: z.object({ cpu: z.string().min(1), memory: z.string().min(1) }).optional()
57
+ })
58
+ .optional()
59
+ });
60
+
61
+ export const CloudflareQueuesConfigSchema = z.object({
62
+ /** Maximum batch size per message. */
63
+ maxBatchSize: z.number().int().positive().default(10),
64
+ /** Maximum retry count. */
65
+ maxRetries: z.number().int().nonnegative().default(3),
66
+ /** Dead-letter queue id. */
67
+ deadLetterQueue: z.string().min(1).optional()
68
+ });
69
+
70
+ export const QueueConfigSchema = z.union([
71
+ DoksQueueConfigSchema.extend({ adapter: z.literal('doks-statefulset') }),
72
+ CloudflareQueuesConfigSchema.extend({ adapter: z.literal('cloudflare-queues') })
73
+ ]);
74
+
75
+ export const QueueDescriptorSchema = QueueBaseSchema.extend({
76
+ /**
77
+ * Adapter-specific configuration. Discriminated union — each adapter
78
+ * package defines its own config schema under its discriminator key.
79
+ */
80
+ config: QueueConfigSchema.optional()
81
+ });
82
+
83
+ export type QueueDescriptor = z.infer<typeof QueueDescriptorSchema>;
84
+
85
+ class DefaultQueueImplementation {
86
+ constructor(
87
+ public readonly descriptor: RuntimeDescriptor,
88
+ public readonly context: unknown
89
+ ) {}
90
+
91
+ get config(): QueueDescriptor {
92
+ return this.descriptor as QueueDescriptor;
93
+ }
94
+ }
95
+
96
+ export const queueKind = createRuntimeKind<QueueDescriptor, DefaultQueueImplementation>({
97
+ id: 'infra/queue',
98
+ descriptorSchema: QueueDescriptorSchema,
99
+ defaultImplementation: DefaultQueueImplementation,
100
+ discoveryPattern: INFRA_DISCOVERY_PATTERN,
101
+ extractStem
102
+ });
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Infra RUM (Real User Monitoring) Kind
3
+ *
4
+ * Provider-agnostic schema for beacon-based front-end telemetry —
5
+ * page-load timing, Core Web Vitals, navigation timing. Provider impls
6
+ * map this shape onto native services:
7
+ *
8
+ * cloudflare-web-analytics → CF Web Analytics (sites + auto-injection rules)
9
+ * sentry-replay → Sentry Performance + Session Replay
10
+ * plausible → Plausible Analytics
11
+ *
12
+ * The kind decouples *configuration* (which hostnames, which token,
13
+ * which privacy mode) from *delivery* (how the beacon `<script>` tag
14
+ * lands in the HTML). For SvelteKit apps, the
15
+ * `@vibesdotdev/cloudflare-web-analytics` package provides a `handle`
16
+ * hook that injects the beacon via `transformPageChunk` — no
17
+ * per-app `app.html` edits required once the kind is wired in.
18
+ */
19
+
20
+ import * as z from 'zod/v4';
21
+ import { createRuntimeKind } from '@vibesdotdev/runtime/factory/kind';
22
+ import { RuntimeDescriptorSchema } from '@vibesdotdev/runtime/schemas/descriptor';
23
+ import { INFRA_DISCOVERY_PATTERN, extractStem } from './discovery.ts';
24
+
25
+ const RumPrivacySchema = z.object({
26
+ /** Drop EU visitor data at the beacon level (GDPR fast path). */
27
+ excludeEU: z.boolean().default(false),
28
+ /** Honor Do-Not-Track / Global Privacy Control headers. */
29
+ respectDoNotTrack: z.boolean().default(true),
30
+ /** Strip PII (query params, fragments) from reported URLs. */
31
+ stripQueryParams: z.boolean().default(false)
32
+ });
33
+
34
+ export type RumPrivacy = z.infer<typeof RumPrivacySchema>;
35
+
36
+ /**
37
+ * Where + how the beacon `<script>` lands in the served HTML.
38
+ *
39
+ * app-html → bake the snippet into app.html (manual; pre-Phase 3)
40
+ * sveltekit-hook → injected via `transformPageChunk` in handle hook (preferred)
41
+ * provider-auto → provider auto-injection (CF: only works on non-Worker traffic)
42
+ * custom → caller injects however they want; we just track config
43
+ */
44
+ const RumInjectionSchema = z.enum([
45
+ 'app-html',
46
+ 'sveltekit-hook',
47
+ 'provider-auto',
48
+ 'custom'
49
+ ]);
50
+
51
+ export type RumInjection = z.infer<typeof RumInjectionSchema>;
52
+
53
+ const RumBaseSchema = RuntimeDescriptorSchema.extend({
54
+ kind: z.literal('infra/rum'),
55
+ adapter: z.string().min(1),
56
+ adapterConfig: z.record(z.string(), z.unknown()).optional(),
57
+ environment: z.string().default('local'),
58
+ /**
59
+ * Public site token (a.k.a. site_tag / beacon token / measurement
60
+ * id). Provider-specific format; safe to commit because it's
61
+ * embedded in client-side HTML for every visitor to see.
62
+ *
63
+ * Pass `{ source: 'secret', key: 'NAME' }` only when the provider
64
+ * explicitly wants a private token — most don't.
65
+ */
66
+ siteToken: z.union([
67
+ z.string().min(1),
68
+ z.object({ source: z.literal('secret'), key: z.string().min(1) })
69
+ ]),
70
+ /** Hostnames the beacon should report from. `*` matches all subdomains. */
71
+ hostnames: z.array(z.string().min(1)).default(['*']),
72
+ injection: RumInjectionSchema.default('sveltekit-hook'),
73
+ privacy: RumPrivacySchema.default(() => ({
74
+ excludeEU: false,
75
+ respectDoNotTrack: true,
76
+ stripQueryParams: false
77
+ })),
78
+ /** Whether the site is currently enabled. Provider impls read+write this. */
79
+ enabled: z.boolean().default(true)
80
+ });
81
+
82
+ export type InfraRumDescriptor = z.infer<typeof RumBaseSchema>;
83
+ export type InfraRumDescriptorInput = z.input<typeof RumBaseSchema>;
84
+
85
+ /**
86
+ * Snapshot of a single configured RUM site on the provider. Returned
87
+ * by `listSites`; consumed by the CLI for table rendering and drift
88
+ * detection.
89
+ */
90
+ export interface RumSiteSnapshot {
91
+ /** Provider-assigned site id (CF: site_tag). */
92
+ siteTag: string;
93
+ /** Friendly name (often the apex hostname). */
94
+ name?: string;
95
+ hostnames: string[];
96
+ enabled: boolean;
97
+ injection?: RumInjection;
98
+ /** Page-views captured in the last 24h (when available). */
99
+ pageViews24h?: number;
100
+ createdAt?: string;
101
+ }
102
+
103
+ export interface RumImplementation {
104
+ /** Enumerate the configured RUM sites on the provider. */
105
+ listSites(): Promise<RumSiteSnapshot[]>;
106
+ /** Look up a single site by siteTag. */
107
+ getSite(siteTag: string): Promise<RumSiteSnapshot | null>;
108
+ /**
109
+ * Ensure a site exists matching the descriptor; returns the
110
+ * siteTag (provider-assigned id) and whether it was created or
111
+ * already existed.
112
+ */
113
+ ensureSite(descriptor: InfraRumDescriptor): Promise<{
114
+ siteTag: string;
115
+ created: boolean;
116
+ }>;
117
+ /** Toggle enabled state. */
118
+ setEnabled(siteTag: string, enabled: boolean): Promise<void>;
119
+ }
120
+
121
+ export const rumKind = createRuntimeKind<InfraRumDescriptor, RumImplementation>({
122
+ id: 'infra/rum',
123
+ descriptorSchema: RumBaseSchema,
124
+ discoveryPattern: INFRA_DISCOVERY_PATTERN,
125
+ extractStem
126
+ });
127
+
128
+ export type InfraRumKind = InfraRumDescriptor;
129
+ export type InfraRumKindInput = InfraRumDescriptorInput;
130
+
131
+ export {
132
+ RumBaseSchema as InfraRumDescriptorSchema,
133
+ RumPrivacySchema,
134
+ RumInjectionSchema
135
+ };