create-kelpie 0.6.0 → 0.8.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.
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,0FAA0F;IAC1F,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,qEAAqE;IACrE,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,qEAAqE;IACrE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,wEAAwE;AACxE,qBAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AA4DD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAkBtD;AAED,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,SAAS,MAAM,EAAE,CAsBpE"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,0FAA0F;IAC1F,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,qEAAqE;IACrE,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,qEAAqE;IACrE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,wEAAwE;AACxE,qBAAa,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AA6DD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAkBtD;AAED,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,SAAS,MAAM,EAAE,CAsBpE"}
package/dist/scaffold.js CHANGED
@@ -29,6 +29,7 @@ const TEMPLATE_FILES = new Map([
29
29
  ['kelpie.config.ts', 'kelpie.config.ts'],
30
30
  ['kelpie.ui.config.ts', 'kelpie.ui.config.ts'],
31
31
  ['src/server.ts', 'src/server.ts'],
32
+ ['src/migrate.ts', 'src/migrate.ts'],
32
33
  ['src/reseal.ts', 'src/reseal.ts'],
33
34
  ['web/index.html', 'web/index.html'],
34
35
  ['web/main.tsx', 'web/main.tsx'],
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-kelpie",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Scaffold a self-hosted Kelpie assembly. Run it with npm create kelpie.",
5
5
  "keywords": [
6
6
  "kelpie",
package/src/scaffold.ts CHANGED
@@ -50,6 +50,7 @@ const TEMPLATE_FILES: ReadonlyMap<string, string> = new Map([
50
50
  ['kelpie.config.ts', 'kelpie.config.ts'],
51
51
  ['kelpie.ui.config.ts', 'kelpie.ui.config.ts'],
52
52
  ['src/server.ts', 'src/server.ts'],
53
+ ['src/migrate.ts', 'src/migrate.ts'],
53
54
  ['src/reseal.ts', 'src/reseal.ts'],
54
55
  ['web/index.html', 'web/index.html'],
55
56
  ['web/main.tsx', 'web/main.tsx'],
@@ -6,6 +6,10 @@ These files are yours. Kelpie itself arrives as `@kelpie/server` and
6
6
  `@kelpie/ui` in `node_modules`; what is checked in here is the assembly that
7
7
  composes them: which modules are on, and how the service starts.
8
8
 
9
+ Full documentation, including production deployment and the complete
10
+ configuration reference, lives at
11
+ <https://github.com/velvet-tiger/kelpie/tree/main/docs>.
12
+
9
13
  ## Running it
10
14
 
11
15
  ```bash
@@ -60,7 +64,9 @@ on an unknown id or an unmet dependency rather than starting without it.
60
64
 
61
65
  Everything below is required unless marked optional or conditional on another
62
66
  variable's value. A missing or invalid value stops the service at boot and
63
- lists every problem at once.
67
+ lists every problem at once. The full reference — including reverse-proxy,
68
+ egress, module-locking, and per-account login-limit settings — is
69
+ [docs/self-hosting/configuration.md](https://github.com/velvet-tiger/kelpie/blob/main/docs/self-hosting/configuration.md).
64
70
 
65
71
  | Variable | Values |
66
72
  | --- | --- |
@@ -85,6 +91,7 @@ lists every problem at once.
85
91
  | `RATE_LIMIT_FORMS_LIMIT` / `RATE_LIMIT_FORMS_WINDOW_SECONDS` | Optional. Requests per window per IP on a public form submit, default 20 / 60 |
86
92
  | `RATE_LIMIT_AUTH_LIMIT` / `RATE_LIMIT_AUTH_WINDOW_SECONDS` | Optional. Requests per window per IP on signup, login, and password reset, default 10 / 60 |
87
93
  | `RATE_LIMIT_API_LIMIT` / `RATE_LIMIT_API_WINDOW_SECONDS` | Optional. Requests per window per API key on the rest of `/v1`, default 600 / 60 |
94
+ | `TRUSTED_PROXY_HOP_COUNT` | Optional, default 0. The number of reverse proxies in front of the service. Set the real hop count so rate limits meter the actual client from `X-Forwarded-For`, not your proxy |
88
95
 
89
96
  ### Rotating the encryption key
90
97
 
@@ -99,6 +106,9 @@ unreadable, so rotate rather than replace:
99
106
  Safe to run more than once.
100
107
  4. Remove `SECRET_ENCRYPTION_KEY_PREVIOUS` and deploy again.
101
108
 
109
+ More detail, including backups and what is sealed under the key:
110
+ [docs/self-hosting/production.md](https://github.com/velvet-tiger/kelpie/blob/main/docs/self-hosting/production.md).
111
+
102
112
  ## Deploying
103
113
 
104
114
  `npm run dev` runs two processes. Vite builds the pages as you edit them and
@@ -117,7 +127,11 @@ One process now serves the pages and the API on `PORT`. Boot fails if
117
127
  stops rather than answering every browser with a blank page.
118
128
 
119
129
  Migrations apply at boot. Running more than one instance makes that a race, so
120
- migrate once in a release step and start the instances with `--no-migrate`.
130
+ migrate once with `npm run migrate` in a release step, then start the instances
131
+ with `--no-migrate`. That command is forward-only and safe to re-run.
132
+
133
+ TLS, reverse proxies, systemd, health checks, and backups:
134
+ [docs/self-hosting/production.md](https://github.com/velvet-tiger/kelpie/blob/main/docs/self-hosting/production.md).
121
135
 
122
136
  ## Upgrading
123
137
 
@@ -57,6 +57,10 @@ export default defineKelpieConfig({
57
57
 
58
58
  webBundleDirectory: fromEnv<string | undefined>('WEB_BUNDLE_DIR', z.string().min(1).optional(), undefined),
59
59
  moduleConfigPath: fromEnv<string | undefined>('KELPIE_MODULE_CONFIG_PATH', z.string().min(1).optional(), undefined),
60
+ // A human-readable name for this install ("dev", "demo", "cloud"). Read by
61
+ // the browser through `GET /v1/public/config` and shown at the top of the
62
+ // UI on non-production runs.
63
+ siteName: fromEnv<string | undefined>('KELPIE_SITE_NAME', z.string().min(1).optional(), undefined),
60
64
  trustedProxyHopCount: fromEnv('TRUSTED_PROXY_HOP_COUNT', nonNegativeInt, 0),
61
65
 
62
66
  // The deployment's base URL. Every emailed link (invite, password reset,
@@ -11,6 +11,7 @@
11
11
  "dev:api": "node --watch --env-file-if-exists=.env src/server.ts",
12
12
  "dev:web": "vite",
13
13
  "start": "node --env-file-if-exists=.env src/server.ts",
14
+ "migrate": "node --env-file-if-exists=.env src/migrate.ts",
14
15
  "reseal": "node --env-file-if-exists=.env src/reseal.ts",
15
16
  "build": "vite build",
16
17
  "typecheck": "tsc --project tsconfig.server.json && tsc --project tsconfig.web.json"
@@ -0,0 +1,59 @@
1
+ import {
2
+ ConfigurationError,
3
+ ModuleBootError,
4
+ ModuleConfigFileError,
5
+ bootAssembly,
6
+ runMigrations,
7
+ } from '@kelpie/server'
8
+
9
+ import kelpieConfig from '../kelpie.config.ts'
10
+
11
+ /**
12
+ * Applies every pending migration, then exits.
13
+ *
14
+ * This is the release step `--no-migrate` expects: run it once before starting
15
+ * instances that skip boot-time migration, so applying migrations is not a race
16
+ * between them. Registration runs first, because modules declare their
17
+ * migrations directory while registering and there is nothing to migrate until
18
+ * that pass has finished. Migrations are forward-only and safe to re-run; a
19
+ * second run is a no-op.
20
+ */
21
+
22
+ function reportFatal(message: string): void {
23
+ process.stderr.write(`${message}\n`)
24
+ }
25
+
26
+ async function migrate(): Promise<void> {
27
+ const { database, contributions, logger } = await bootAssembly(kelpieConfig, process.env)
28
+
29
+ try {
30
+ await runMigrations(database.db, contributions.schemas, logger)
31
+ } finally {
32
+ await database.close()
33
+ }
34
+ }
35
+
36
+ try {
37
+ await migrate()
38
+ process.exit(0)
39
+ } catch (error: unknown) {
40
+ if (error instanceof ConfigurationError) {
41
+ reportFatal(error.message)
42
+ reportFatal('Check .env against the table in README.md.')
43
+ process.exit(1)
44
+ }
45
+
46
+ if (error instanceof ModuleConfigFileError) {
47
+ reportFatal(error.message)
48
+ reportFatal('Fix the file at KELPIE_MODULE_CONFIG_PATH, or unset it to let workspaces decide for themselves.')
49
+ process.exit(1)
50
+ }
51
+
52
+ if (error instanceof ModuleBootError) {
53
+ reportFatal(error.message)
54
+ reportFatal('Fix the module list in kelpie.config.ts, or the configuration it needs.')
55
+ process.exit(1)
56
+ }
57
+
58
+ throw error
59
+ }
@@ -5,22 +5,12 @@ import {
5
5
  ModuleBootError,
6
6
  ModuleConfigFileError,
7
7
  WebBundleError,
8
- connectDatabase,
8
+ bootAssembly,
9
9
  createApp,
10
- createEventBus,
11
- createIdFactory,
12
- createLogger,
13
- createTransactionScope,
14
- createTransportForDestination,
15
- readModuleConfigFile,
16
- registerModules,
17
- resolveActorFrom,
18
10
  resolveClientIpFrom,
19
- resolveKelpieConfig,
20
11
  runMigrations,
21
12
  serveWebBundle,
22
13
  } from '@kelpie/server'
23
- import type { CredentialDependencies } from '@kelpie/server'
24
14
 
25
15
  import kelpieConfig from '../kelpie.config.ts'
26
16
 
@@ -28,12 +18,13 @@ import kelpieConfig from '../kelpie.config.ts'
28
18
  * The entry point. It reads the environment, registers the configured modules,
29
19
  * applies migrations, wires the dependencies, and serves.
30
20
  *
31
- * Registration runs before migrations. Modules declare their migrations
32
- * directory while registering, so there is nothing to migrate until that pass
33
- * has finished.
21
+ * The config, database, and registration pass come from `bootAssembly`, shared
22
+ * with the standalone `migrate` command. Registration runs before migrations:
23
+ * modules declare their migrations directory while registering, so there is
24
+ * nothing to migrate until that pass has finished.
34
25
  *
35
- * `--no-migrate` skips the migration step, for deployments where one release
36
- * step migrates and many instances then start.
26
+ * `--no-migrate` skips the migration step, for deployments where `npm run migrate`
27
+ * migrates once in a release step and many instances then start.
37
28
  */
38
29
 
39
30
  function reportFatal(message: string): void {
@@ -41,37 +32,10 @@ function reportFatal(message: string): void {
41
32
  }
42
33
 
43
34
  async function start(): Promise<void> {
44
- const config = resolveKelpieConfig(kelpieConfig, process.env)
45
- const logger = createLogger({
46
- level: config.logging.level,
47
- transports: config.logging.destinations.map(createTransportForDestination),
48
- })
49
- const database = connectDatabase(config.databaseUrl, logger)
50
- const events = createEventBus(logger)
51
- const createId = createIdFactory()
52
- const credentials: CredentialDependencies = { db: database.db, now: () => new Date() }
53
- const moduleConfig = readModuleConfigFile(config.moduleConfigPath)
54
- const contributions = await registerModules({
55
- modules: kelpieConfig.modules,
56
- environment: config.env,
57
- logger,
58
- events,
59
- moduleConfig,
60
- resolveActor: (context) => resolveActorFrom(credentials, context),
61
- services: {
62
- db: database.db,
63
- transaction: createTransactionScope({ db: database.db, bus: events, logger, createId }),
64
- createId,
65
- now: () => new Date(),
66
- appBaseUrl: config.appBaseUrl,
67
- secretEncryption: config.secretEncryption,
68
- },
69
- // `provider` picks a named sender from the runtime's registry. `'log'` is
70
- // built in; `'smtp'` is registered by the built-in `smtp-email` core
71
- // module; other names come from third-party provider modules listed in
72
- // `kelpie.config.ts`. `from` is the address on every outgoing message.
73
- email: { provider: config.email.EMAIL_PROVIDER, from: config.email.EMAIL_FROM },
74
- })
35
+ const { config, logger, database, createId, credentials, contributions } = await bootAssembly(
36
+ kelpieConfig,
37
+ process.env,
38
+ )
75
39
 
76
40
  if (process.argv.includes('--no-migrate')) {
77
41
  logger.info('skipping migrations', { reason: '--no-migrate' })
@@ -86,6 +50,8 @@ async function start(): Promise<void> {
86
50
  credentials,
87
51
  createId,
88
52
  rateLimit: config.rateLimit,
53
+ runtimeMode: config.runtimeMode,
54
+ siteName: config.siteName,
89
55
  // The socket address, then `X-Forwarded-For` only as far as the configured
90
56
  // number of trusted proxies allows. Resolved from the connection itself
91
57
  // rather than defaulted inside `createApp`, and trusting the header any