@micacms/runtime 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +16 -0
  2. package/dist/app.d.ts +62 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +107 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/config.d.ts +187 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +154 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/context.d.ts +121 -0
  11. package/dist/context.d.ts.map +1 -0
  12. package/dist/context.js +117 -0
  13. package/dist/context.js.map +1 -0
  14. package/dist/db/driver.d.ts +35 -0
  15. package/dist/db/driver.d.ts.map +1 -0
  16. package/dist/db/driver.js +95 -0
  17. package/dist/db/driver.js.map +1 -0
  18. package/dist/http.d.ts +40 -0
  19. package/dist/http.d.ts.map +1 -0
  20. package/dist/http.js +38 -0
  21. package/dist/http.js.map +1 -0
  22. package/dist/index.d.ts +31 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +31 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/lib/errors.d.ts +39 -0
  27. package/dist/lib/errors.d.ts.map +1 -0
  28. package/dist/lib/errors.js +52 -0
  29. package/dist/lib/errors.js.map +1 -0
  30. package/dist/lib/file-type.d.ts +26 -0
  31. package/dist/lib/file-type.d.ts.map +1 -0
  32. package/dist/lib/file-type.js +89 -0
  33. package/dist/lib/file-type.js.map +1 -0
  34. package/dist/lib/git.d.ts +29 -0
  35. package/dist/lib/git.d.ts.map +1 -0
  36. package/dist/lib/git.js +62 -0
  37. package/dist/lib/git.js.map +1 -0
  38. package/dist/lib/id.d.ts +13 -0
  39. package/dist/lib/id.d.ts.map +1 -0
  40. package/dist/lib/id.js +56 -0
  41. package/dist/lib/id.js.map +1 -0
  42. package/dist/lib/logger.d.ts +20 -0
  43. package/dist/lib/logger.d.ts.map +1 -0
  44. package/dist/lib/logger.js +65 -0
  45. package/dist/lib/logger.js.map +1 -0
  46. package/dist/lib/ports.d.ts +17 -0
  47. package/dist/lib/ports.d.ts.map +1 -0
  48. package/dist/lib/ports.js +17 -0
  49. package/dist/lib/ports.js.map +1 -0
  50. package/dist/lib/rate-limit.d.ts +29 -0
  51. package/dist/lib/rate-limit.d.ts.map +1 -0
  52. package/dist/lib/rate-limit.js +47 -0
  53. package/dist/lib/rate-limit.js.map +1 -0
  54. package/dist/lib/schema-stats.d.ts +64 -0
  55. package/dist/lib/schema-stats.d.ts.map +1 -0
  56. package/dist/lib/schema-stats.js +103 -0
  57. package/dist/lib/schema-stats.js.map +1 -0
  58. package/dist/lib/version.d.ts +14 -0
  59. package/dist/lib/version.d.ts.map +1 -0
  60. package/dist/lib/version.js +25 -0
  61. package/dist/lib/version.js.map +1 -0
  62. package/dist/middleware/index.d.ts +41 -0
  63. package/dist/middleware/index.d.ts.map +1 -0
  64. package/dist/middleware/index.js +142 -0
  65. package/dist/middleware/index.js.map +1 -0
  66. package/dist/routes/admin-content.d.ts +22 -0
  67. package/dist/routes/admin-content.d.ts.map +1 -0
  68. package/dist/routes/admin-content.js +194 -0
  69. package/dist/routes/admin-content.js.map +1 -0
  70. package/dist/routes/admin-media.d.ts +19 -0
  71. package/dist/routes/admin-media.d.ts.map +1 -0
  72. package/dist/routes/admin-media.js +81 -0
  73. package/dist/routes/admin-media.js.map +1 -0
  74. package/dist/routes/admin-spa.d.ts +13 -0
  75. package/dist/routes/admin-spa.d.ts.map +1 -0
  76. package/dist/routes/admin-spa.js +72 -0
  77. package/dist/routes/admin-spa.js.map +1 -0
  78. package/dist/routes/admin-staging.d.ts +15 -0
  79. package/dist/routes/admin-staging.d.ts.map +1 -0
  80. package/dist/routes/admin-staging.js +90 -0
  81. package/dist/routes/admin-staging.js.map +1 -0
  82. package/dist/routes/admin-system.d.ts +14 -0
  83. package/dist/routes/admin-system.d.ts.map +1 -0
  84. package/dist/routes/admin-system.js +153 -0
  85. package/dist/routes/admin-system.js.map +1 -0
  86. package/dist/routes/health.d.ts +12 -0
  87. package/dist/routes/health.d.ts.map +1 -0
  88. package/dist/routes/health.js +44 -0
  89. package/dist/routes/health.js.map +1 -0
  90. package/dist/schema.d.ts +56 -0
  91. package/dist/schema.d.ts.map +1 -0
  92. package/dist/schema.js +173 -0
  93. package/dist/schema.js.map +1 -0
  94. package/dist/server.d.ts +28 -0
  95. package/dist/server.d.ts.map +1 -0
  96. package/dist/server.js +47 -0
  97. package/dist/server.js.map +1 -0
  98. package/dist/services/media.d.ts +65 -0
  99. package/dist/services/media.d.ts.map +1 -0
  100. package/dist/services/media.js +180 -0
  101. package/dist/services/media.js.map +1 -0
  102. package/dist/services/staging-local.d.ts +58 -0
  103. package/dist/services/staging-local.d.ts.map +1 -0
  104. package/dist/services/staging-local.js +391 -0
  105. package/dist/services/staging-local.js.map +1 -0
  106. package/dist/services/staging.d.ts +167 -0
  107. package/dist/services/staging.d.ts.map +1 -0
  108. package/dist/services/staging.js +333 -0
  109. package/dist/services/staging.js.map +1 -0
  110. package/package.json +49 -0
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # @micacms/runtime
2
+
3
+ > **Experimental.** Pre-1.0: the API can still change without notice.
4
+
5
+ The single-site Mica runtime: the Hono API, application services and staging
6
+ orchestration, deliberately **authentication-neutral**. It answers "who is
7
+ this request?" with whatever `AuthSurface` the composing app hands in, and
8
+ never imports an auth implementation — that direction is what keeps
9
+ `npx @micacms/editor` free of authentication code.
10
+
11
+ You normally do not depend on this package directly. The two compositions do:
12
+
13
+ - [`@micacms/editor`](https://www.npmjs.com/package/@micacms/editor) — the
14
+ local editor: loopback, no auth, no database.
15
+ - [`@micacms/self-hosted`](https://www.npmjs.com/package/@micacms/self-hosted)
16
+ — the Docker composition, behind `@micacms/auth-oidc`.
package/dist/app.d.ts ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Application assembly.
3
+ *
4
+ * cms.example.com
5
+ * │
6
+ * ▼
7
+ * Hono
8
+ * ┌──────┴───┬──────────┐
9
+ * │ │ │
10
+ * /api/* /admin/* /health
11
+ * │ │
12
+ * connector Vue SPA
13
+ * │
14
+ * content repository
15
+ *
16
+ * There is no public content API and no `/media/*`. A website is built from the
17
+ * repository, not from this server, so nothing here has to be reachable for a
18
+ * site to deploy — or to stay up.
19
+ *
20
+ * Authentication is not assembled here — it is *received*. The composing app
21
+ * hands in an `AuthSurface`: routes for `/api/auth`, and the gate applied in
22
+ * front of every admin route. The self-hosted app passes the OIDC surface
23
+ * from `@micacms/auth-oidc`; the local editor passes nothing and gets the
24
+ * unauthenticated surface below, which is a statement of fact — on your own
25
+ * machine there is nobody to be — not a bypass of anything.
26
+ */
27
+ import { Hono } from "hono";
28
+ import type { MiddlewareHandler } from "hono";
29
+ import type { RuntimeContext } from "./context.js";
30
+ import type { Env } from "./http.js";
31
+ /** What a composing app contributes around the auth-neutral runtime. */
32
+ export interface AuthSurface {
33
+ /** Mounted at `/api/auth`: sign-in, callback, logout, whatever auth needs. */
34
+ routes: Hono<Env>;
35
+ /**
36
+ * Applied before every `/api/admin` route, in order. Must either set the
37
+ * `access` variable or refuse the request — nothing behind it runs without
38
+ * an `AccessContext`.
39
+ */
40
+ gate: MiddlewareHandler<Env>[];
41
+ }
42
+ /**
43
+ * The unauthenticated surface: every request is allowed, and none is anybody.
44
+ *
45
+ * An authorization policy, not authentication code. It exists so action
46
+ * checks stay uniform without inventing a user, and it is safe only because
47
+ * the local editor is loopback-bound and Host-guarded by construction.
48
+ */
49
+ export declare function allowAll(): MiddlewareHandler<Env>;
50
+ export interface CreateAppOptions {
51
+ /** Absent means the unauthenticated local surface. */
52
+ auth?: AuthSurface;
53
+ /**
54
+ * Extra middleware in front of everything — the local editor's Host
55
+ * allowlist goes here, so even /health answers only to this machine.
56
+ */
57
+ guards?: MiddlewareHandler<Env>[];
58
+ /** Where the built admin SPA is served from. */
59
+ adminDir?: string;
60
+ }
61
+ export declare function createApp(ctx: RuntimeContext, options?: CreateAppOptions): Hono<Env>;
62
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAgBrC,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC1B,8EAA8E;IAC9E,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAClB;;;;OAIG;IACH,IAAI,EAAE,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;CAChC;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAKjD;AASD,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;IAClC,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,GAAE,gBAAqB,GAAG,IAAI,CAAC,GAAG,CAAC,CA4ExF"}
package/dist/app.js ADDED
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Application assembly.
3
+ *
4
+ * cms.example.com
5
+ * │
6
+ * ▼
7
+ * Hono
8
+ * ┌──────┴───┬──────────┐
9
+ * │ │ │
10
+ * /api/* /admin/* /health
11
+ * │ │
12
+ * connector Vue SPA
13
+ * │
14
+ * content repository
15
+ *
16
+ * There is no public content API and no `/media/*`. A website is built from the
17
+ * repository, not from this server, so nothing here has to be reachable for a
18
+ * site to deploy — or to stay up.
19
+ *
20
+ * Authentication is not assembled here — it is *received*. The composing app
21
+ * hands in an `AuthSurface`: routes for `/api/auth`, and the gate applied in
22
+ * front of every admin route. The self-hosted app passes the OIDC surface
23
+ * from `@micacms/auth-oidc`; the local editor passes nothing and gets the
24
+ * unauthenticated surface below, which is a statement of fact — on your own
25
+ * machine there is nobody to be — not a bypass of anything.
26
+ */
27
+ import { Hono } from "hono";
28
+ import { cors } from "hono/cors";
29
+ import { allowedOrigins, errorHandler, originGuard, rateLimit, requestContext, securityHeaders, } from "./middleware/index.js";
30
+ import { adminContentRoutes } from "./routes/admin-content.js";
31
+ import { adminMediaRoutes } from "./routes/admin-media.js";
32
+ import { adminSpaRoutes, adminAssetsExist } from "./routes/admin-spa.js";
33
+ import { adminStagingRoutes } from "./routes/admin-staging.js";
34
+ import { adminSystemRoutes } from "./routes/admin-system.js";
35
+ import { healthRoutes } from "./routes/health.js";
36
+ /**
37
+ * The unauthenticated surface: every request is allowed, and none is anybody.
38
+ *
39
+ * An authorization policy, not authentication code. It exists so action
40
+ * checks stay uniform without inventing a user, and it is safe only because
41
+ * the local editor is loopback-bound and Host-guarded by construction.
42
+ */
43
+ export function allowAll() {
44
+ return async (c, next) => {
45
+ c.set("access", { identity: null });
46
+ await next();
47
+ };
48
+ }
49
+ /** `/api/auth/config` with nothing behind it: the SPA's cue to skip sign-in. */
50
+ function unauthenticatedSurface() {
51
+ const routes = new Hono();
52
+ routes.get("/config", (c) => c.json({ authRequired: false, provider: null }));
53
+ return { routes, gate: [allowAll()] };
54
+ }
55
+ export function createApp(ctx, options = {}) {
56
+ const app = new Hono();
57
+ const auth = options.auth ?? unauthenticatedSurface();
58
+ /* ---------------------------------------------------------- baseline */
59
+ app.use("*", requestContext(ctx));
60
+ for (const guard of options.guards ?? [])
61
+ app.use("*", guard);
62
+ app.use("*", securityHeaders());
63
+ app.onError(errorHandler());
64
+ /* ------------------------------------------------------------ health */
65
+ app.route("/health", healthRoutes());
66
+ /* --------------------------------------------------------------- API */
67
+ // In development the SPA is served by Vite on another origin, so the API has
68
+ // to accept credentialed cross-origin calls from it. In production the SPA is
69
+ // same-origin and ADMIN_ORIGINS is normally empty.
70
+ if (ctx.config.adminOrigins.length > 0) {
71
+ app.use("/api/*", cors({
72
+ origin: allowedOrigins(ctx.config),
73
+ credentials: true,
74
+ allowHeaders: ["content-type", "x-csrf-token"],
75
+ allowMethods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
76
+ }));
77
+ }
78
+ app.use("/api/*", rateLimit());
79
+ app.use("/api/*", originGuard());
80
+ app.route("/api/auth", auth.routes);
81
+ /* ------------------------------------------------------- admin API */
82
+ // One gate, and no second one behind it: whoever the surface admits is an
83
+ // editor of this site. There are no roles, because there are no accounts to
84
+ // hang them on.
85
+ for (const middleware of auth.gate)
86
+ app.use("/api/admin/*", middleware);
87
+ app.route("/api/admin", adminSystemRoutes());
88
+ app.route("/api/admin", adminContentRoutes());
89
+ app.route("/api/admin", adminStagingRoutes());
90
+ app.route("/api/admin/media", adminMediaRoutes());
91
+ app.all("/api/*", (c) => c.json({ error: { code: "not_found", message: "No such endpoint." } }, 404));
92
+ /* --------------------------------------------------------- admin SPA */
93
+ const adminDir = options.adminDir ?? ctx.config.ADMIN_DIR;
94
+ if (adminDir && adminAssetsExist(adminDir)) {
95
+ app.route("/admin", adminSpaRoutes(adminDir));
96
+ }
97
+ else {
98
+ // Running from source with only the API built: point at the Vite server
99
+ // rather than returning a blank 404.
100
+ app.get("/admin/*", (c) => c.text("The admin interface has not been built.\n" +
101
+ "Run `rush build`, or use `rush dev` and open the Vite dev server.", 503));
102
+ }
103
+ app.get("/", (c) => c.redirect("/admin/"));
104
+ app.notFound((c) => c.text("Not found", 404));
105
+ return app;
106
+ }
107
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * The runtime's slice of the environment, as a fragment.
3
+ *
4
+ * There is no `loadConfig` here, deliberately. The runtime is composed by an
5
+ * app — the local editor, the self-hosted container — and which variables
6
+ * exist, which are refused and what the defaults are is exactly what makes
7
+ * one app not the other. Each app builds its own Zod schema from this shape,
8
+ * adds its own variables, and derives a `RuntimeConfig` with `deriveRuntime`;
9
+ * this module only states what the runtime itself reads.
10
+ *
11
+ * `MICA_MODE` is gone. The mode is which app you run.
12
+ */
13
+ import { z } from "zod";
14
+ /**
15
+ * `.default` takes the *output* value in Zod 4, and short-circuits: an absent
16
+ * variable returns the boolean without going through the transform.
17
+ */
18
+ export declare const bool: (fallback: boolean) => z.ZodDefault<z.ZodPipe<z.ZodEnum<{
19
+ 0: "0";
20
+ 1: "1";
21
+ true: "true";
22
+ false: "false";
23
+ }>, z.ZodTransform<boolean, "0" | "1" | "true" | "false">>>;
24
+ /** `a, b , c` and `a,b,c` are the same list, and an empty entry is not one. */
25
+ export declare const list: (value: string | undefined) => string[];
26
+ export declare class ConfigError extends Error {
27
+ name: string;
28
+ }
29
+ /** Hostnames that are this machine, and nowhere else. */
30
+ export declare const LOOPBACK: Set<string>;
31
+ /** The variables the runtime itself reads. Apps spread this into their schema. */
32
+ export declare const runtimeEnv: {
33
+ NODE_ENV: z.ZodDefault<z.ZodEnum<{
34
+ development: "development";
35
+ test: "test";
36
+ production: "production";
37
+ }>>;
38
+ LOG_LEVEL: z.ZodDefault<z.ZodEnum<{
39
+ debug: "debug";
40
+ info: "info";
41
+ warn: "warn";
42
+ error: "error";
43
+ silent: "silent";
44
+ }>>;
45
+ /** The address to listen on. Defaulted by the app: loopback for the local
46
+ * editor (which refuses anything else), every interface for a container. */
47
+ HOST: z.ZodOptional<z.ZodString>;
48
+ PORT: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
49
+ /** Public origin of the CMS itself. Used for cookies, CORS and media URLs. */
50
+ MICA_PUBLIC_URL: z.ZodDefault<z.ZodString>;
51
+ /**
52
+ * The content repository this Mica serves, when it reaches it as a working
53
+ * tree on disk. Ignored for a provider connector, which is given
54
+ * REPOSITORY_ROOT inside the remote repository instead.
55
+ */
56
+ CONTENT_ROOT: z.ZodDefault<z.ZodString>;
57
+ /**
58
+ * How Mica reaches that repository. `local` is a working tree beside the
59
+ * server — and the working tree is then the draft workspace. `github` and
60
+ * `gitlab` publish through the provider's API, with saves staged in the
61
+ * draft store until an editor publishes.
62
+ */
63
+ REPOSITORY: z.ZodDefault<z.ZodEnum<{
64
+ local: "local";
65
+ github: "github";
66
+ gitlab: "gitlab";
67
+ }>>;
68
+ /** Where the content root sits *inside* the remote repository. */
69
+ REPOSITORY_ROOT: z.ZodDefault<z.ZodString>;
70
+ REPOSITORY_BRANCH: z.ZodDefault<z.ZodString>;
71
+ /** Token with write access to the content repository. */
72
+ REPOSITORY_TOKEN: z.ZodOptional<z.ZodString>;
73
+ /** `owner/repo` for GitHub, `group/project` or a numeric id for GitLab. */
74
+ REPOSITORY_PROJECT: z.ZodOptional<z.ZodString>;
75
+ /** For GitHub Enterprise or self-managed GitLab. */
76
+ REPOSITORY_API_BASE: z.ZodOptional<z.ZodString>;
77
+ /**
78
+ * Whether working-tree staging may commit and push. `false` reduces Publish
79
+ * to autosave plus a read-only view of the pending changes.
80
+ */
81
+ MICA_LOCAL_PUBLISH: z.ZodDefault<z.ZodPipe<z.ZodEnum<{
82
+ 0: "0";
83
+ 1: "1";
84
+ true: "true";
85
+ false: "false";
86
+ }>, z.ZodTransform<boolean, "0" | "1" | "true" | "false">>>;
87
+ MAX_UPLOAD_BYTES: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
88
+ /** Read the client IP from X-Forwarded-For. Only enable behind a proxy. */
89
+ TRUST_PROXY: z.ZodDefault<z.ZodPipe<z.ZodEnum<{
90
+ 0: "0";
91
+ 1: "1";
92
+ true: "true";
93
+ false: "false";
94
+ }>, z.ZodTransform<boolean, "0" | "1" | "true" | "false">>>;
95
+ /** Extra browser origins allowed to call the admin API (dev Vite server). */
96
+ ADMIN_ORIGINS: z.ZodOptional<z.ZodString>;
97
+ /** Overrides where the built admin SPA is served from. */
98
+ ADMIN_DIR: z.ZodOptional<z.ZodString>;
99
+ };
100
+ declare const runtimeSchema: z.ZodObject<{
101
+ NODE_ENV: z.ZodDefault<z.ZodEnum<{
102
+ development: "development";
103
+ test: "test";
104
+ production: "production";
105
+ }>>;
106
+ LOG_LEVEL: z.ZodDefault<z.ZodEnum<{
107
+ debug: "debug";
108
+ info: "info";
109
+ warn: "warn";
110
+ error: "error";
111
+ silent: "silent";
112
+ }>>;
113
+ HOST: z.ZodOptional<z.ZodString>;
114
+ PORT: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
115
+ MICA_PUBLIC_URL: z.ZodDefault<z.ZodString>;
116
+ CONTENT_ROOT: z.ZodDefault<z.ZodString>;
117
+ REPOSITORY: z.ZodDefault<z.ZodEnum<{
118
+ local: "local";
119
+ github: "github";
120
+ gitlab: "gitlab";
121
+ }>>;
122
+ REPOSITORY_ROOT: z.ZodDefault<z.ZodString>;
123
+ REPOSITORY_BRANCH: z.ZodDefault<z.ZodString>;
124
+ REPOSITORY_TOKEN: z.ZodOptional<z.ZodString>;
125
+ REPOSITORY_PROJECT: z.ZodOptional<z.ZodString>;
126
+ REPOSITORY_API_BASE: z.ZodOptional<z.ZodString>;
127
+ MICA_LOCAL_PUBLISH: z.ZodDefault<z.ZodPipe<z.ZodEnum<{
128
+ 0: "0";
129
+ 1: "1";
130
+ true: "true";
131
+ false: "false";
132
+ }>, z.ZodTransform<boolean, "0" | "1" | "true" | "false">>>;
133
+ MAX_UPLOAD_BYTES: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
134
+ TRUST_PROXY: z.ZodDefault<z.ZodPipe<z.ZodEnum<{
135
+ 0: "0";
136
+ 1: "1";
137
+ true: "true";
138
+ false: "false";
139
+ }>, z.ZodTransform<boolean, "0" | "1" | "true" | "false">>>;
140
+ ADMIN_ORIGINS: z.ZodOptional<z.ZodString>;
141
+ ADMIN_DIR: z.ZodOptional<z.ZodString>;
142
+ }, z.core.$strip>;
143
+ export type RuntimeEnv = z.infer<typeof runtimeSchema>;
144
+ /**
145
+ * The derived values the runtime reads, on top of the parsed environment.
146
+ *
147
+ * Called from each app's own `transform`, so every composition derives them
148
+ * the same way and none forgets one.
149
+ */
150
+ export declare function deriveRuntime<T extends RuntimeEnv>(env: T): T & {
151
+ isProduction: boolean;
152
+ contentRoot: string;
153
+ adminOrigins: string[];
154
+ };
155
+ /** What the runtime requires of a finished configuration. */
156
+ export type RuntimeConfig = ReturnType<typeof deriveRuntime<RuntimeEnv>> & {
157
+ /** Resolved by the app: the runtime never guesses an address. */
158
+ HOST: string;
159
+ };
160
+ /**
161
+ * A remote repository needs to be told which one, and with what.
162
+ *
163
+ * Checked at startup rather than at the first save: a Mica that starts, shows
164
+ * the editor their content, and only fails when they press Save has already
165
+ * wasted their work.
166
+ */
167
+ export declare function requireRepositoryConfig(config: RuntimeConfig): void;
168
+ /**
169
+ * Folds `./.env` into the ambient environment.
170
+ *
171
+ * `process.loadEnvFile` leaves already-set variables alone, so a container's
172
+ * `environment:` block still beats a file that happened to be copied into the
173
+ * image.
174
+ */
175
+ export declare function loadEnvFile(): void;
176
+ /**
177
+ * An unset variable and one set to the empty string mean the same thing.
178
+ *
179
+ * `.env.example` ships blanks for the operator to fill in, and the docs say to
180
+ * copy it verbatim; without this, doing so reads as "the secret is a
181
+ * zero-length string" and the server refuses on the documented happy path.
182
+ */
183
+ export declare function withoutBlanks(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
184
+ /** Formats a Zod refusal the way a person at a terminal reads it. */
185
+ export declare function describeConfigIssues(error: z.ZodError): string;
186
+ export {};
187
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;GAGG;AACH,eAAO,MAAM,IAAI,GAAI,UAAU,OAAO;;;;;2DAIhB,CAAC;AAEvB,+EAA+E;AAC/E,eAAO,MAAM,IAAI,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,MAAM,EAInC,CAAC;AAErB,qBAAa,WAAY,SAAQ,KAAK;IAC3B,IAAI,SAAiB;CAC/B;AAED,yDAAyD;AACzD,eAAO,MAAM,QAAQ,aAAyE,CAAC;AAE/F,kFAAkF;AAClF,eAAO,MAAM,UAAU;;;;;;;;;;;;;IAIrB;iFAC6E;;;IAI7E,8EAA8E;;IAG9E;;;;OAIG;;IAGH;;;;;OAKG;;;;;;IAEH,kEAAkE;;;IAGlE,yDAAyD;;IAEzD,2EAA2E;;IAE3E,oDAAoD;;IAGpD;;;OAGG;;;;;;;;IASH,2EAA2E;;;;;;;IAE3E,6EAA6E;;IAE7E,0DAA0D;;CAE3D,CAAC;AAEF,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAuB,CAAC;AAC3C,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEvD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,UAAU,EAAE,GAAG,EAAE,CAAC;;;;EAOzD;AAED,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,UAAU,CAAC,CAAC,GAAG;IACzE,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAgBnE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAWlC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAIvE;AAED,qEAAqE;AACrE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,MAAM,CAK9D"}
package/dist/config.js ADDED
@@ -0,0 +1,154 @@
1
+ /**
2
+ * The runtime's slice of the environment, as a fragment.
3
+ *
4
+ * There is no `loadConfig` here, deliberately. The runtime is composed by an
5
+ * app — the local editor, the self-hosted container — and which variables
6
+ * exist, which are refused and what the defaults are is exactly what makes
7
+ * one app not the other. Each app builds its own Zod schema from this shape,
8
+ * adds its own variables, and derives a `RuntimeConfig` with `deriveRuntime`;
9
+ * this module only states what the runtime itself reads.
10
+ *
11
+ * `MICA_MODE` is gone. The mode is which app you run.
12
+ */
13
+ import path from "node:path";
14
+ import { z } from "zod";
15
+ import { DEFAULT_BASE_URL, DEFAULT_PORT } from "./lib/ports.js";
16
+ /**
17
+ * `.default` takes the *output* value in Zod 4, and short-circuits: an absent
18
+ * variable returns the boolean without going through the transform.
19
+ */
20
+ export const bool = (fallback) => z
21
+ .enum(["true", "false", "1", "0"])
22
+ .transform((value) => value === "true" || value === "1")
23
+ .default(fallback);
24
+ /** `a, b , c` and `a,b,c` are the same list, and an empty entry is not one. */
25
+ export const list = (value) => (value ?? "")
26
+ .split(",")
27
+ .map((entry) => entry.trim())
28
+ .filter(Boolean);
29
+ export class ConfigError extends Error {
30
+ name = "ConfigError";
31
+ }
32
+ /** Hostnames that are this machine, and nowhere else. */
33
+ export const LOOPBACK = new Set(["localhost", "127.0.0.1", "[::1]", "::1", "0:0:0:0:0:0:0:1"]);
34
+ /** The variables the runtime itself reads. Apps spread this into their schema. */
35
+ export const runtimeEnv = {
36
+ NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
37
+ LOG_LEVEL: z.enum(["debug", "info", "warn", "error", "silent"]).default("info"),
38
+ /** The address to listen on. Defaulted by the app: loopback for the local
39
+ * editor (which refuses anything else), every interface for a container. */
40
+ HOST: z.string().optional(),
41
+ PORT: z.coerce.number().int().min(1).max(65535).default(DEFAULT_PORT),
42
+ /** Public origin of the CMS itself. Used for cookies, CORS and media URLs. */
43
+ MICA_PUBLIC_URL: z.string().url().default(DEFAULT_BASE_URL),
44
+ /**
45
+ * The content repository this Mica serves, when it reaches it as a working
46
+ * tree on disk. Ignored for a provider connector, which is given
47
+ * REPOSITORY_ROOT inside the remote repository instead.
48
+ */
49
+ CONTENT_ROOT: z.string().default("../../examples/muster-consulting/content"),
50
+ /**
51
+ * How Mica reaches that repository. `local` is a working tree beside the
52
+ * server — and the working tree is then the draft workspace. `github` and
53
+ * `gitlab` publish through the provider's API, with saves staged in the
54
+ * draft store until an editor publishes.
55
+ */
56
+ REPOSITORY: z.enum(["local", "github", "gitlab"]).default("local"),
57
+ /** Where the content root sits *inside* the remote repository. */
58
+ REPOSITORY_ROOT: z.string().default("content"),
59
+ REPOSITORY_BRANCH: z.string().default("main"),
60
+ /** Token with write access to the content repository. */
61
+ REPOSITORY_TOKEN: z.string().optional(),
62
+ /** `owner/repo` for GitHub, `group/project` or a numeric id for GitLab. */
63
+ REPOSITORY_PROJECT: z.string().optional(),
64
+ /** For GitHub Enterprise or self-managed GitLab. */
65
+ REPOSITORY_API_BASE: z.string().url().optional(),
66
+ /**
67
+ * Whether working-tree staging may commit and push. `false` reduces Publish
68
+ * to autosave plus a read-only view of the pending changes.
69
+ */
70
+ MICA_LOCAL_PUBLISH: bool(true),
71
+ MAX_UPLOAD_BYTES: z.coerce
72
+ .number()
73
+ .int()
74
+ .positive()
75
+ .default(25 * 1024 * 1024),
76
+ /** Read the client IP from X-Forwarded-For. Only enable behind a proxy. */
77
+ TRUST_PROXY: bool(false),
78
+ /** Extra browser origins allowed to call the admin API (dev Vite server). */
79
+ ADMIN_ORIGINS: z.string().optional(),
80
+ /** Overrides where the built admin SPA is served from. */
81
+ ADMIN_DIR: z.string().optional(),
82
+ };
83
+ const runtimeSchema = z.object(runtimeEnv);
84
+ /**
85
+ * The derived values the runtime reads, on top of the parsed environment.
86
+ *
87
+ * Called from each app's own `transform`, so every composition derives them
88
+ * the same way and none forgets one.
89
+ */
90
+ export function deriveRuntime(env) {
91
+ return {
92
+ ...env,
93
+ isProduction: env.NODE_ENV === "production",
94
+ contentRoot: path.resolve(env.CONTENT_ROOT),
95
+ adminOrigins: list(env.ADMIN_ORIGINS),
96
+ };
97
+ }
98
+ /**
99
+ * A remote repository needs to be told which one, and with what.
100
+ *
101
+ * Checked at startup rather than at the first save: a Mica that starts, shows
102
+ * the editor their content, and only fails when they press Save has already
103
+ * wasted their work.
104
+ */
105
+ export function requireRepositoryConfig(config) {
106
+ if (config.REPOSITORY === "local")
107
+ return;
108
+ const needed = ["REPOSITORY_PROJECT", "REPOSITORY_TOKEN"].filter((key) => !config[key]);
109
+ if (needed.length > 0) {
110
+ throw new ConfigError(`REPOSITORY is "${config.REPOSITORY}", so ${needed.join(" and ")} must be set.\n` +
111
+ (config.REPOSITORY === "github"
112
+ ? " REPOSITORY_PROJECT is owner/repo, and the token needs contents: write."
113
+ : " REPOSITORY_PROJECT is group/project or a numeric id, and the token needs\n" +
114
+ " the write_repository scope."));
115
+ }
116
+ }
117
+ /**
118
+ * Folds `./.env` into the ambient environment.
119
+ *
120
+ * `process.loadEnvFile` leaves already-set variables alone, so a container's
121
+ * `environment:` block still beats a file that happened to be copied into the
122
+ * image.
123
+ */
124
+ export function loadEnvFile() {
125
+ try {
126
+ process.loadEnvFile();
127
+ }
128
+ catch (error) {
129
+ // No `.env` is the normal case in production. Anything else — unreadable,
130
+ // malformed — is a real misconfiguration, and silently starting with
131
+ // default secrets is exactly the failure config exists to prevent.
132
+ if (error.code !== "ENOENT") {
133
+ throw new ConfigError(`Could not read .env: ${error.message}`);
134
+ }
135
+ }
136
+ }
137
+ /**
138
+ * An unset variable and one set to the empty string mean the same thing.
139
+ *
140
+ * `.env.example` ships blanks for the operator to fill in, and the docs say to
141
+ * copy it verbatim; without this, doing so reads as "the secret is a
142
+ * zero-length string" and the server refuses on the documented happy path.
143
+ */
144
+ export function withoutBlanks(env) {
145
+ return Object.fromEntries(Object.entries(env).filter(([, value]) => value !== undefined && value.trim() !== ""));
146
+ }
147
+ /** Formats a Zod refusal the way a person at a terminal reads it. */
148
+ export function describeConfigIssues(error) {
149
+ const details = error.issues
150
+ .map((issue) => ` ${issue.path.join(".") || "(root)"}: ${issue.message}`)
151
+ .join("\n");
152
+ return `Invalid environment configuration:\n${details}`;
153
+ }
154
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}