mfeflow 0.0.0-stage → 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.
Files changed (120) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +126 -2
  3. package/assets/features/analytics-gtm/feature.json +117 -0
  4. package/assets/features/analytics-gtm/files/Analytics.tsx +13 -0
  5. package/assets/features/analytics-gtm/files/ConsentBanner.tsx +47 -0
  6. package/assets/features/analytics-gtm/files/consent-banner-test.tsx +36 -0
  7. package/assets/features/analytics-gtm/files/init.ts +26 -0
  8. package/assets/features/analytics-gtm/files/remote-analytics-test.ts.eta +18 -0
  9. package/assets/features/analytics-gtm/files/remote-analytics.ts.eta +13 -0
  10. package/assets/features/analytics-gtm/files/shell-init-test.ts +42 -0
  11. package/assets/features/ci-github/feature.json +26 -0
  12. package/assets/features/ci-github/files/ci.md +41 -0
  13. package/assets/features/ci-github/files/ci.yml +63 -0
  14. package/assets/features/env-t3/feature.json +378 -0
  15. package/assets/features/env-t3/files/check-runtime-config.ts +105 -0
  16. package/assets/features/env-t3/files/env.arktype.ts +12 -0
  17. package/assets/features/env-t3/files/env.example +1 -0
  18. package/assets/features/env-t3/files/env.valibot.ts +12 -0
  19. package/assets/features/env-t3/files/env.zod.ts +12 -0
  20. package/assets/features/env-t3/files/runtime.ts.eta +30 -0
  21. package/assets/features/env-t3/files/schema.arktype.ts +8 -0
  22. package/assets/features/env-t3/files/schema.valibot.ts +8 -0
  23. package/assets/features/env-t3/files/schema.zod.ts +8 -0
  24. package/assets/features/git-hooks/feature.json +42 -0
  25. package/assets/features/git-hooks/files/commitlint.config.js +1 -0
  26. package/assets/features/git-hooks/files/lefthook.yml +9 -0
  27. package/assets/features/lint-oxlint/feature.json +60 -0
  28. package/assets/features/lint-oxlint/files/oxlintrc.json +5 -0
  29. package/assets/features/lint-oxlint/files/prettierignore +5 -0
  30. package/assets/features/lint-oxlint/files/prettierrc.json +5 -0
  31. package/assets/features/telemetry-otel/feature.json +159 -0
  32. package/assets/features/telemetry-otel/files/init.ts.eta +53 -0
  33. package/assets/features/telemetry-otel/files/remote-telemetry-test.ts.eta +13 -0
  34. package/assets/features/telemetry-otel/files/remote-telemetry.ts.eta +11 -0
  35. package/assets/features/telemetry-otel/files/shell-init-test.ts.eta +36 -0
  36. package/assets/features/testing/feature.json +202 -0
  37. package/assets/features/testing/files/handlers.ts +5 -0
  38. package/assets/features/testing/files/playwright.config.ts +30 -0
  39. package/assets/features/testing/files/root-vitest.config.ts +6 -0
  40. package/assets/features/testing/files/sample-handlers-test.ts +16 -0
  41. package/assets/features/testing/files/sample-remote-test.tsx +12 -0
  42. package/assets/features/testing/files/sample-shell-test.tsx +11 -0
  43. package/assets/features/testing/files/sample-smoke-e2e.ts +53 -0
  44. package/assets/features/testing/files/server.ts +4 -0
  45. package/assets/features/testing/files/setup.ts +18 -0
  46. package/assets/features/testing/files/vitest.config.ts +11 -0
  47. package/assets/features/tsconfig/feature.json +78 -0
  48. package/assets/features/tsconfig/files/root.tsconfig.json +4 -0
  49. package/assets/features/tsconfig/files/tsconfig.json +5 -0
  50. package/assets/features/url-factory/feature.json +30 -0
  51. package/assets/features/url-factory/files/endpoints.ts +12 -0
  52. package/assets/templates/monorepo/feature.json +295 -0
  53. package/assets/templates/monorepo/files/remote/mfe.json.eta +7 -0
  54. package/assets/templates/monorepo/files/remote/package.json.eta +6 -0
  55. package/assets/templates/monorepo/files/remote/rsbuild.config.ts.eta +7 -0
  56. package/assets/templates/monorepo/files/remote/src/bootstrap.tsx.eta +6 -0
  57. package/assets/templates/monorepo/files/remote/src/env.d.ts.eta +1 -0
  58. package/assets/templates/monorepo/files/remote/src/exposed/App.tsx.eta +18 -0
  59. package/assets/templates/monorepo/files/remote/src/index.ts.eta +2 -0
  60. package/assets/templates/monorepo/files/root/AGENTS.md.eta +17 -0
  61. package/assets/templates/monorepo/files/root/README.md.eta +52 -0
  62. package/assets/templates/monorepo/files/root/gitignore.eta +11 -0
  63. package/assets/templates/monorepo/files/root/nvmrc.eta +1 -0
  64. package/assets/templates/monorepo/files/root/package.json.eta +9 -0
  65. package/assets/templates/monorepo/files/root/pnpm-workspace.yaml.eta +7 -0
  66. package/assets/templates/monorepo/files/root/turbo.json.eta +16 -0
  67. package/assets/templates/monorepo/files/shell/mfe.json.eta +7 -0
  68. package/assets/templates/monorepo/files/shell/package.json.eta +6 -0
  69. package/assets/templates/monorepo/files/shell/rsbuild.config.ts.eta +74 -0
  70. package/assets/templates/monorepo/files/shell/src/App.tsx.eta +46 -0
  71. package/assets/templates/monorepo/files/shell/src/bootstrap.tsx.eta +24 -0
  72. package/assets/templates/monorepo/files/shell/src/env.d.ts.eta +1 -0
  73. package/assets/templates/monorepo/files/shell/src/index.ts.eta +4 -0
  74. package/assets/templates/monorepo/files/shell/src/pages/Home.tsx.eta +12 -0
  75. package/assets/templates/monorepo/files/shell/src/remotes/route-table.tsx.eta +12 -0
  76. package/assets/templates/monorepo/glue/registry-entry.json.eta +5 -0
  77. package/assets/templates/monorepo/glue/route.tsx.eta +5 -0
  78. package/bin/mfeflow.js +4 -0
  79. package/dist/args.d.ts +68 -0
  80. package/dist/assets.d.ts +13 -0
  81. package/dist/catalog.d.ts +24 -0
  82. package/dist/checks/compat.d.ts +2 -0
  83. package/dist/checks/config.d.ts +8 -0
  84. package/dist/checks/env.d.ts +6 -0
  85. package/dist/checks/index.d.ts +6 -0
  86. package/dist/checks/plugins.d.ts +4 -0
  87. package/dist/checks/singletons.d.ts +9 -0
  88. package/dist/checks/workspace.d.ts +2 -0
  89. package/dist/cli.d.ts +11 -0
  90. package/dist/commands/add.d.ts +84 -0
  91. package/dist/commands/budget.d.ts +56 -0
  92. package/dist/commands/dev.d.ts +62 -0
  93. package/dist/commands/doctor.d.ts +141 -0
  94. package/dist/commands/env-key.d.ts +4 -0
  95. package/dist/commands/features.d.ts +53 -0
  96. package/dist/commands/init.d.ts +102 -0
  97. package/dist/devregistry.d.ts +19 -0
  98. package/dist/exit.d.ts +31 -0
  99. package/dist/findings.d.ts +35 -0
  100. package/dist/glue.d.ts +41 -0
  101. package/dist/help.d.ts +12 -0
  102. package/dist/index.d.ts +8 -0
  103. package/dist/index.js +4154 -0
  104. package/dist/inspect.d.ts +57 -0
  105. package/dist/io.d.ts +10 -0
  106. package/dist/local.d.ts +28 -0
  107. package/dist/options.d.ts +7 -0
  108. package/dist/output.d.ts +157 -0
  109. package/dist/pipeline.d.ts +7 -0
  110. package/dist/preset.d.ts +19 -0
  111. package/dist/proc.d.ts +79 -0
  112. package/dist/prompter.d.ts +28 -0
  113. package/dist/report.d.ts +26 -0
  114. package/dist/runtime.d.ts +17 -0
  115. package/dist/singletons.d.ts +11 -0
  116. package/dist/sizes.d.ts +17 -0
  117. package/dist/system.d.ts +20 -0
  118. package/dist/version.d.ts +8 -0
  119. package/dist/write.d.ts +26 -0
  120. package/package.json +66 -3
@@ -0,0 +1,378 @@
1
+ {
2
+ "name": "env-t3",
3
+ "version": "0.1.0",
4
+ "description": "Typed env with t3-env: env.ts per app fails the build on a missing variable, runtime-config schema checked before deploy, no validator or env value in the browser bundle.",
5
+ "requires": ["core", "tsconfig"],
6
+ "prompts": [
7
+ {
8
+ "name": "validator",
9
+ "type": "select",
10
+ "message": "Validator for env.ts and the runtime-config schema",
11
+ "choices": ["zod", "valibot", "arktype"],
12
+ "default": "zod"
13
+ }
14
+ ],
15
+ "files": [
16
+ {
17
+ "to": "env.ts",
18
+ "target": "root",
19
+ "from": "files/env.zod.ts",
20
+ "when": {
21
+ "validator": "zod"
22
+ }
23
+ },
24
+ {
25
+ "to": "env.ts",
26
+ "target": "root",
27
+ "from": "files/env.valibot.ts",
28
+ "when": {
29
+ "validator": "valibot"
30
+ }
31
+ },
32
+ {
33
+ "to": "env.ts",
34
+ "target": "root",
35
+ "from": "files/env.arktype.ts",
36
+ "when": {
37
+ "validator": "arktype"
38
+ }
39
+ },
40
+ {
41
+ "to": ".env.example",
42
+ "target": "root",
43
+ "from": "files/env.example"
44
+ },
45
+ {
46
+ "to": "scripts/check-runtime-config.ts",
47
+ "target": "root",
48
+ "from": "files/check-runtime-config.ts"
49
+ },
50
+ {
51
+ "to": "env.ts",
52
+ "target": "shell",
53
+ "from": "files/env.zod.ts",
54
+ "when": {
55
+ "validator": "zod"
56
+ }
57
+ },
58
+ {
59
+ "to": "env.ts",
60
+ "target": "shell",
61
+ "from": "files/env.valibot.ts",
62
+ "when": {
63
+ "validator": "valibot"
64
+ }
65
+ },
66
+ {
67
+ "to": "env.ts",
68
+ "target": "shell",
69
+ "from": "files/env.arktype.ts",
70
+ "when": {
71
+ "validator": "arktype"
72
+ }
73
+ },
74
+ {
75
+ "to": ".env.example",
76
+ "target": "shell",
77
+ "from": "files/env.example"
78
+ },
79
+ {
80
+ "to": "env.ts",
81
+ "target": "remotes",
82
+ "from": "files/env.zod.ts",
83
+ "when": {
84
+ "validator": "zod"
85
+ }
86
+ },
87
+ {
88
+ "to": "env.ts",
89
+ "target": "remotes",
90
+ "from": "files/env.valibot.ts",
91
+ "when": {
92
+ "validator": "valibot"
93
+ }
94
+ },
95
+ {
96
+ "to": "env.ts",
97
+ "target": "remotes",
98
+ "from": "files/env.arktype.ts",
99
+ "when": {
100
+ "validator": "arktype"
101
+ }
102
+ },
103
+ {
104
+ "to": ".env.example",
105
+ "target": "remotes",
106
+ "from": "files/env.example"
107
+ },
108
+ {
109
+ "to": "src/config/schema.ts",
110
+ "target": "shell",
111
+ "from": "files/schema.zod.ts",
112
+ "when": {
113
+ "validator": "zod"
114
+ }
115
+ },
116
+ {
117
+ "to": "src/config/schema.ts",
118
+ "target": "shell",
119
+ "from": "files/schema.valibot.ts",
120
+ "when": {
121
+ "validator": "valibot"
122
+ }
123
+ },
124
+ {
125
+ "to": "src/config/schema.ts",
126
+ "target": "shell",
127
+ "from": "files/schema.arktype.ts",
128
+ "when": {
129
+ "validator": "arktype"
130
+ }
131
+ },
132
+ {
133
+ "to": "src/config/runtime.ts",
134
+ "target": "shell",
135
+ "from": "files/runtime.ts.eta",
136
+ "template": true
137
+ },
138
+ {
139
+ "to": "public/config/runtime-config.dev.json",
140
+ "target": "shell",
141
+ "content": "{\n \"environment\": \"dev\"\n}\n"
142
+ },
143
+ {
144
+ "to": "public/config/runtime-config.staging.json",
145
+ "target": "shell",
146
+ "content": "{\n \"environment\": \"staging\"\n}\n"
147
+ },
148
+ {
149
+ "to": "public/config/runtime-config.prod.json",
150
+ "target": "shell",
151
+ "content": "{\n \"environment\": \"prod\"\n}\n"
152
+ }
153
+ ],
154
+ "dependencies": [
155
+ {
156
+ "name": "@t3-oss/env-core",
157
+ "range": "0.13.11",
158
+ "target": "root",
159
+ "dev": true
160
+ },
161
+ {
162
+ "name": "@t3-oss/env-core",
163
+ "range": "0.13.11",
164
+ "target": "shell",
165
+ "dev": true
166
+ },
167
+ {
168
+ "name": "@t3-oss/env-core",
169
+ "range": "0.13.11",
170
+ "target": "remotes",
171
+ "dev": true
172
+ },
173
+ {
174
+ "name": "zod",
175
+ "range": "4.6.7",
176
+ "target": "root",
177
+ "dev": true,
178
+ "when": {
179
+ "validator": "zod"
180
+ }
181
+ },
182
+ {
183
+ "name": "zod",
184
+ "range": "4.6.7",
185
+ "target": "shell",
186
+ "dev": true,
187
+ "when": {
188
+ "validator": "zod"
189
+ }
190
+ },
191
+ {
192
+ "name": "zod",
193
+ "range": "4.6.7",
194
+ "target": "remotes",
195
+ "dev": true,
196
+ "when": {
197
+ "validator": "zod"
198
+ }
199
+ },
200
+ {
201
+ "name": "valibot",
202
+ "range": "1.5.0",
203
+ "target": "root",
204
+ "dev": true,
205
+ "when": {
206
+ "validator": "valibot"
207
+ }
208
+ },
209
+ {
210
+ "name": "valibot",
211
+ "range": "1.5.0",
212
+ "target": "shell",
213
+ "dev": true,
214
+ "when": {
215
+ "validator": "valibot"
216
+ }
217
+ },
218
+ {
219
+ "name": "valibot",
220
+ "range": "1.5.0",
221
+ "target": "remotes",
222
+ "dev": true,
223
+ "when": {
224
+ "validator": "valibot"
225
+ }
226
+ },
227
+ {
228
+ "name": "arktype",
229
+ "range": "2.2.9",
230
+ "target": "root",
231
+ "dev": true,
232
+ "when": {
233
+ "validator": "arktype"
234
+ }
235
+ },
236
+ {
237
+ "name": "arktype",
238
+ "range": "2.2.9",
239
+ "target": "shell",
240
+ "dev": true,
241
+ "when": {
242
+ "validator": "arktype"
243
+ }
244
+ },
245
+ {
246
+ "name": "arktype",
247
+ "range": "2.2.9",
248
+ "target": "remotes",
249
+ "dev": true,
250
+ "when": {
251
+ "validator": "arktype"
252
+ }
253
+ },
254
+ {
255
+ "name": "@types/node",
256
+ "range": "26.6.6",
257
+ "target": "root",
258
+ "dev": true
259
+ }
260
+ ],
261
+ "scripts": [
262
+ {
263
+ "name": "check:runtime-config",
264
+ "command": "node --experimental-strip-types scripts/check-runtime-config.ts",
265
+ "target": "root"
266
+ },
267
+ {
268
+ "name": "typecheck:tooling",
269
+ "command": "tsc --noEmit",
270
+ "target": "root"
271
+ }
272
+ ],
273
+ "transforms": [
274
+ {
275
+ "op": "add-import",
276
+ "file": "rsbuild.config.ts",
277
+ "target": "shell",
278
+ "from": "./env"
279
+ },
280
+ {
281
+ "op": "add-import",
282
+ "file": "rsbuild.config.ts",
283
+ "target": "remotes",
284
+ "from": "./env"
285
+ },
286
+ {
287
+ "op": "add-boot-step",
288
+ "file": "src/bootstrap.tsx",
289
+ "target": "shell",
290
+ "call": "loadRuntimeConfig",
291
+ "from": "./config/runtime"
292
+ },
293
+ {
294
+ "op": "add-env-key",
295
+ "file": "src/config/schema.ts",
296
+ "target": "shell",
297
+ "key": "gtmId",
298
+ "scope": "runtime",
299
+ "schema": {
300
+ "zod": "z.string().regex(/^(GTM-[A-Z0-9]{4,12})?$/)",
301
+ "valibot": "v.pipe(v.string(), v.regex(/^(GTM-[A-Z0-9]{4,12})?$/))",
302
+ "arktype": "'/^(GTM-[A-Z0-9]{4,12})?$/'"
303
+ },
304
+ "value": "",
305
+ "configFiles": [
306
+ "public/config/runtime-config.dev.json",
307
+ "public/config/runtime-config.staging.json",
308
+ "public/config/runtime-config.prod.json"
309
+ ],
310
+ "when": {
311
+ "feature:analytics-gtm": true
312
+ }
313
+ },
314
+ {
315
+ "op": "add-env-key",
316
+ "file": "src/config/schema.ts",
317
+ "target": "shell",
318
+ "key": "otlpEndpoint",
319
+ "scope": "runtime",
320
+ "schema": {
321
+ "zod": "z.string().regex(/^(https?:[/][/][^\\s]+)?$/)",
322
+ "valibot": "v.pipe(v.string(), v.regex(/^(https?:[/][/][^\\s]+)?$/))",
323
+ "arktype": "\"'' | string.url\""
324
+ },
325
+ "value": "",
326
+ "configFiles": [
327
+ "public/config/runtime-config.dev.json",
328
+ "public/config/runtime-config.staging.json",
329
+ "public/config/runtime-config.prod.json"
330
+ ],
331
+ "when": {
332
+ "feature:telemetry-otel": true
333
+ }
334
+ },
335
+ {
336
+ "op": "add-env-key",
337
+ "file": "src/config/schema.ts",
338
+ "target": "shell",
339
+ "key": "traceSampleRatio",
340
+ "scope": "runtime",
341
+ "schema": {
342
+ "zod": "z.number().min(0).max(1)",
343
+ "valibot": "v.pipe(v.number(), v.minValue(0), v.maxValue(1))",
344
+ "arktype": "'0 <= number <= 1'"
345
+ },
346
+ "value": 1,
347
+ "configFiles": [
348
+ "public/config/runtime-config.dev.json",
349
+ "public/config/runtime-config.staging.json",
350
+ "public/config/runtime-config.prod.json"
351
+ ],
352
+ "when": {
353
+ "feature:telemetry-otel": true
354
+ }
355
+ },
356
+ {
357
+ "op": "add-env-key",
358
+ "file": "src/config/schema.ts",
359
+ "target": "shell",
360
+ "key": "propagateTraceHeaderCorsUrls",
361
+ "scope": "runtime",
362
+ "schema": {
363
+ "zod": "z.array(z.string())",
364
+ "valibot": "v.array(v.string())",
365
+ "arktype": "'string[]'"
366
+ },
367
+ "value": [],
368
+ "configFiles": [
369
+ "public/config/runtime-config.dev.json",
370
+ "public/config/runtime-config.staging.json",
371
+ "public/config/runtime-config.prod.json"
372
+ ],
373
+ "when": {
374
+ "feature:telemetry-otel": true
375
+ }
376
+ }
377
+ ]
378
+ }
@@ -0,0 +1,105 @@
1
+ // Validates every public/config/runtime-config*.json against the schema in the same app's
2
+ // src/config/schema.ts. Run it before a deploy: pnpm check:runtime-config [env ...]
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { pathToFileURL } from 'node:url';
6
+
7
+ interface Issue {
8
+ message: string;
9
+ path?: readonly unknown[];
10
+ }
11
+
12
+ type Result = { issues?: readonly Issue[] };
13
+
14
+ interface StandardSchema {
15
+ '~standard': { validate: (value: unknown) => Result | Promise<Result> };
16
+ }
17
+
18
+ interface Outcome {
19
+ checked: number;
20
+ failures: string[];
21
+ }
22
+
23
+ const ENV_FILE = /^runtime-config(?:\.([a-z0-9-]+))?\.json$/;
24
+ const root = process.cwd();
25
+ const wanted = process.argv.slice(2);
26
+
27
+ function isObject(value: unknown): value is object {
28
+ return (typeof value === 'object' || typeof value === 'function') && value !== null;
29
+ }
30
+
31
+ function isStandardSchema(value: unknown): value is StandardSchema {
32
+ if (!isObject(value) || !('~standard' in value)) return false;
33
+ const meta = value['~standard'];
34
+ return isObject(meta) && 'validate' in meta && typeof meta.validate === 'function';
35
+ }
36
+
37
+ function appDirs(): string[] {
38
+ const project: unknown = JSON.parse(fs.readFileSync(path.join(root, 'mfeflow.json'), 'utf8'));
39
+ const apps = isObject(project) && 'apps' in project ? project.apps : undefined;
40
+ if (!isObject(apps)) return [];
41
+ return Object.values(apps).flatMap((app: unknown) =>
42
+ isObject(app) && 'path' in app && typeof app.path === 'string'
43
+ ? [path.join(root, app.path)]
44
+ : [],
45
+ );
46
+ }
47
+
48
+ async function checkFile(schema: StandardSchema, file: string): Promise<string[]> {
49
+ const shown = path.relative(root, file);
50
+ let json: unknown;
51
+ try {
52
+ json = JSON.parse(fs.readFileSync(file, 'utf8'));
53
+ } catch (error) {
54
+ return [`${shown}: not valid JSON (${error instanceof Error ? error.message : String(error)})`];
55
+ }
56
+ const { issues = [] } = await schema['~standard'].validate(json);
57
+ return issues.map((issue) => {
58
+ const at = (issue.path ?? []).map(String).join('.');
59
+ return `${shown}: ${at === '' ? '(root)' : at} ${issue.message}`;
60
+ });
61
+ }
62
+
63
+ async function checkApp(dir: string): Promise<Outcome> {
64
+ const schemaFile = path.join(dir, 'src', 'config', 'schema.ts');
65
+ const configDir = path.join(dir, 'public', 'config');
66
+ if (!fs.existsSync(schemaFile) || !fs.existsSync(configDir)) return { checked: 0, failures: [] };
67
+ const loaded: unknown = await import(pathToFileURL(schemaFile).href);
68
+ const schema =
69
+ isObject(loaded) && 'runtimeConfigSchema' in loaded ? loaded.runtimeConfigSchema : undefined;
70
+ if (!isStandardSchema(schema)) {
71
+ return {
72
+ checked: 0,
73
+ failures: [
74
+ `${path.relative(root, schemaFile)}: runtimeConfigSchema is not a Standard Schema`,
75
+ ],
76
+ };
77
+ }
78
+ const files = fs
79
+ .readdirSync(configDir)
80
+ .toSorted((a, b) => a.localeCompare(b))
81
+ .filter((name) => {
82
+ const match = ENV_FILE.exec(name);
83
+ return match !== null && (wanted.length === 0 || wanted.includes(match[1] ?? ''));
84
+ });
85
+ const results = await Promise.all(
86
+ files.map((name) => checkFile(schema, path.join(configDir, name))),
87
+ );
88
+ return { checked: files.length, failures: results.flat() };
89
+ }
90
+
91
+ const outcomes = await Promise.all(appDirs().map(checkApp));
92
+ const checked = outcomes.reduce((sum, o) => sum + o.checked, 0);
93
+ const failures = outcomes.flatMap((o) => o.failures);
94
+
95
+ for (const line of failures) console.error(line);
96
+ if (checked === 0 && failures.length === 0) {
97
+ console.error(
98
+ wanted.length > 0
99
+ ? `no runtime-config.<env>.json found for ${wanted.join(', ')}`
100
+ : 'no runtime-config files found',
101
+ );
102
+ process.exit(1);
103
+ }
104
+ if (failures.length > 0) process.exit(1);
105
+ console.log(`runtime config ok (${String(checked)} file${checked === 1 ? '' : 's'})`);
@@ -0,0 +1,12 @@
1
+ import { createEnv } from '@t3-oss/env-core';
2
+ import { type } from 'arktype';
3
+
4
+ // Server and build-time variables, checked when a process that imports this file starts.
5
+ // Add one: mfeflow add env-key API_ORIGIN --scope server --schema "type('string.url')"
6
+ export const env = createEnv({
7
+ server: {
8
+ NODE_ENV: type("'development' | 'production' | 'test' | undefined"),
9
+ },
10
+ runtimeEnv: process.env,
11
+ emptyStringAsUndefined: true,
12
+ });
@@ -0,0 +1 @@
1
+ # Variables env.ts checks. Copy to .env and fill in; .env stays out of git.
@@ -0,0 +1,12 @@
1
+ import { createEnv } from '@t3-oss/env-core';
2
+ import * as v from 'valibot';
3
+
4
+ // Server and build-time variables, checked when a process that imports this file starts.
5
+ // Add one: mfeflow add env-key API_ORIGIN --scope server --schema "v.pipe(v.string(), v.url())"
6
+ export const env = createEnv({
7
+ server: {
8
+ NODE_ENV: v.optional(v.picklist(['development', 'production', 'test'])),
9
+ },
10
+ runtimeEnv: process.env,
11
+ emptyStringAsUndefined: true,
12
+ });
@@ -0,0 +1,12 @@
1
+ import { createEnv } from '@t3-oss/env-core';
2
+ import { z } from 'zod';
3
+
4
+ // Server and build-time variables, checked when a process that imports this file starts.
5
+ // Add one: mfeflow add env-key API_ORIGIN --scope server --schema "z.url()"
6
+ export const env = createEnv({
7
+ server: {
8
+ NODE_ENV: z.enum(['development', 'production', 'test']).optional(),
9
+ },
10
+ runtimeEnv: process.env,
11
+ emptyStringAsUndefined: true,
12
+ });
@@ -0,0 +1,30 @@
1
+ import { fetchRuntimeConfig, reportRemoteError } from '@mfeflow/runtime';
2
+ import type { runtimeConfigSchema } from './schema';
3
+
4
+ export type RuntimeConfig = NonNullable<
5
+ (typeof runtimeConfigSchema)['~standard']['types']
6
+ >['output'];
7
+
8
+ const KEY = '__MFE_RUNTIME_CONFIG__';
9
+
10
+ /** The config the shell loaded. Typed from the schema; nothing is validated here, `pnpm check:runtime-config` does that before deploy. */
11
+ export function getRuntimeConfig(): RuntimeConfig {
12
+ const config: unknown = Reflect.get(globalThis, KEY);
13
+ if (config === undefined) {
14
+ throw new Error('getRuntimeConfig() was called before the shell loaded the runtime config');
15
+ }
16
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- the deploy check validated this file against the schema
17
+ return config as RuntimeConfig;
18
+ }
19
+
20
+ /**
21
+ * Fetches the runtime config once at boot, through the loader analytics and telemetry share, so the
22
+ * file is requested once. A failure is reported and leaves the config unset.
23
+ */
24
+ export async function loadRuntimeConfig(url?: string): Promise<void> {
25
+ try {
26
+ await fetchRuntimeConfig(url);
27
+ } catch (error) {
28
+ reportRemoteError('<%= it.app.name %>', 'runtime-config', error);
29
+ }
30
+ }
@@ -0,0 +1,8 @@
1
+ import { type } from 'arktype';
2
+
3
+ // The shape of public/config/runtime-config.<env>.json. The browser only imports this file's type
4
+ // (see ./runtime), so the validator stays out of the bundle; `pnpm check:runtime-config` validates the files.
5
+ // Add a key: mfeflow add env-key GTM_ID --scope runtime --schema "type('string > 0')"
6
+ export const runtimeConfigSchema = type({
7
+ environment: "'dev' | 'staging' | 'prod'",
8
+ });
@@ -0,0 +1,8 @@
1
+ import * as v from 'valibot';
2
+
3
+ // The shape of public/config/runtime-config.<env>.json. The browser only imports this file's type
4
+ // (see ./runtime), so the validator stays out of the bundle; `pnpm check:runtime-config` validates the files.
5
+ // Add a key: mfeflow add env-key GTM_ID --scope runtime --schema "v.pipe(v.string(), v.minLength(1))"
6
+ export const runtimeConfigSchema = v.object({
7
+ environment: v.picklist(['dev', 'staging', 'prod']),
8
+ });
@@ -0,0 +1,8 @@
1
+ import { z } from 'zod';
2
+
3
+ // The shape of public/config/runtime-config.<env>.json. The browser only imports this file's type
4
+ // (see ./runtime), so the validator stays out of the bundle; `pnpm check:runtime-config` validates the files.
5
+ // Add a key: mfeflow add env-key GTM_ID --scope runtime --schema "z.string().min(1)"
6
+ export const runtimeConfigSchema = z.object({
7
+ environment: z.enum(['dev', 'staging', 'prod']),
8
+ });
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "git-hooks",
3
+ "version": "0.1.0",
4
+ "description": "lefthook with commitlint: Conventional Commit messages, typecheck before push. Opt-in.",
5
+ "requires": ["core"],
6
+ "files": [
7
+ {
8
+ "to": "lefthook.yml",
9
+ "from": "files/lefthook.yml"
10
+ },
11
+ {
12
+ "to": "commitlint.config.js",
13
+ "from": "files/commitlint.config.js"
14
+ }
15
+ ],
16
+ "dependencies": [
17
+ {
18
+ "name": "lefthook",
19
+ "range": "2.2.2",
20
+ "target": "root",
21
+ "dev": true
22
+ },
23
+ {
24
+ "name": "@commitlint/cli",
25
+ "range": "21.2.4",
26
+ "target": "root",
27
+ "dev": true
28
+ },
29
+ {
30
+ "name": "@commitlint/config-conventional",
31
+ "range": "21.2.4",
32
+ "target": "root",
33
+ "dev": true
34
+ }
35
+ ],
36
+ "scripts": [
37
+ {
38
+ "name": "prepare",
39
+ "command": "lefthook install"
40
+ }
41
+ ]
42
+ }
@@ -0,0 +1 @@
1
+ export default { extends: ['@commitlint/config-conventional'] };
@@ -0,0 +1,9 @@
1
+ commit-msg:
2
+ commands:
3
+ commitlint:
4
+ run: pnpm commitlint --edit {1}
5
+
6
+ pre-push:
7
+ commands:
8
+ typecheck:
9
+ run: pnpm typecheck