ras-stack 0.46.0 → 0.47.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.
- package/LICENSE +21 -661
- package/README.md +12 -16
- package/dist/create/index.js +16 -2
- package/dist/create/index.js.map +1 -1
- package/{examples/full-stack → dist/create/template}/Dockerfile +8 -8
- package/{examples/full-stack → dist/create/template}/Dockerfile.standalone +2 -1
- package/{examples/full-stack → dist/create/template}/package.json +4 -3
- package/dist/policy/index.js +19 -2
- package/dist/policy/index.js.map +1 -1
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/index.js.map +1 -1
- package/package.json +10 -13
- /package/{examples/full-stack → dist/create/template}/.env.example +0 -0
- /package/{examples/full-stack → dist/create/template}/.oxfmtrc.json +0 -0
- /package/{examples/full-stack → dist/create/template}/centrifugo.json +0 -0
- /package/{examples/full-stack → dist/create/template}/dockerignore.template +0 -0
- /package/{examples/full-stack → dist/create/template}/drizzle/0000_production_reference.sql +0 -0
- /package/{examples/full-stack → dist/create/template}/drizzle/meta/_journal.json +0 -0
- /package/{examples/full-stack → dist/create/template}/e2e/full-stack.spec.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/gitignore.template +0 -0
- /package/{examples/full-stack → dist/create/template}/oxlint.json +0 -0
- /package/{examples/full-stack → dist/create/template}/playwright.config.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/pnpm-workspace.template.yaml +0 -0
- /package/{examples/full-stack → dist/create/template}/ras-stack.assets.json +0 -0
- /package/{examples/full-stack → dist/create/template}/scripts/containerRuntime.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/scripts/database.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/scripts/database.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/client/auth.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/client/queries.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/client/queryClient.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/client/useRealtime.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/posthog.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routeTree.gen.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/router.tsx +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routes/__root.tsx +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routes/api/auth.$.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routes/api/centrifugo.connect.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routes/api/health.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routes/api/live.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routes/api/ready.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routes/api/uploads.$id.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routes/api/uploads.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/routes/index.tsx +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/app.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/app.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/auth-flow.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/auth.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/environment.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/environment.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/fns.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/messages.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/messages.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/migration.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/outbox.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/outbox.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/posthog.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/rate-limit.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/rate-limit.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/rpc.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/schema.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/session.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/session.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/uploads.test.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/server/uploads.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/start.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/src/styles.css +0 -0
- /package/{examples/full-stack → dist/create/template}/tsconfig.json +0 -0
- /package/{examples/full-stack → dist/create/template}/vite.config.ts +0 -0
- /package/{examples/full-stack → dist/create/template}/vitest.config.ts +0 -0
package/README.md
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
1
|
# 🧱 ras-stack
|
|
4
2
|
|
|
5
3
|
**A practical TypeScript stack with strong defaults and room to make it yours.**
|
|
6
4
|
|
|
7
5
|
TanStack Start · React · Better Auth · Drizzle · SQLite/PostgreSQL · Centrifugo · Caddy · PostHog
|
|
8
6
|
|
|
9
|
-
[](https://www.npmjs.com/package/ras-stack) [](https://github.com/richardsolomou/ras-stack/actions/workflows/ci.yml) [](LICENSE)
|
|
10
|
-
|
|
11
|
-
</div>
|
|
7
|
+
[](https://www.npmjs.com/package/ras-stack) [](https://github.com/richardsolomou/ras-stack/actions/workflows/ci.yml) [](https://github.com/richardsolomou/ras-stack/blob/main/packages/ras-stack/LICENSE)
|
|
12
8
|
|
|
13
9
|
I kept rebuilding the same boring parts: secure sessions, origin checks, database startup, realtime connections, process shutdown, CI, previews, and releases. `ras-stack` solves them once with the libraries I would choose anyway.
|
|
14
10
|
|
|
@@ -54,7 +50,7 @@ Applications still configure every upstream library directly. This table describ
|
|
|
54
50
|
|
|
55
51
|
The application keeps schemas, migrations, repositories, routes, authorization, templates, upload rules, realtime payloads, storage, deployment topology, and UI. There is no shared application factory or giant configuration object.
|
|
56
52
|
|
|
57
|
-
The [`examples/full-stack`](examples/full-stack) workspace shows the boundaries together and tests them through `workspace:*`. It is the repository's integration contract and the canonical source for the generated starter; once generated, the application owns its copied code and normal semver dependency.
|
|
53
|
+
The [`examples/full-stack`](https://github.com/richardsolomou/ras-stack/tree/main/examples/full-stack) workspace shows the boundaries together and tests them through `workspace:*`. It is the repository's integration contract and the canonical source for the generated starter; once generated, the application owns its copied code and normal semver dependency.
|
|
58
54
|
|
|
59
55
|
## Pick what you need 🧩
|
|
60
56
|
|
|
@@ -103,17 +99,17 @@ Three reusable workflows provide the standard pull-request preview lifecycle:
|
|
|
103
99
|
- `deploy-dokploy-preview.yml` publishes, resolves, deploys, reports, and removes previews.
|
|
104
100
|
- `prune-dokploy-previews.yml` cleans up applications and images left behind by interrupted runs.
|
|
105
101
|
|
|
106
|
-
Applications supply only their package, application prefix, port, environment template, and optional product hook. They can provide a custom HTTPS domain, optionally manage a prefixed Cloudflare-proxied record for origins that reject direct traffic, or let Dokploy generate an HTTP `sslip.io` address. The shared `DOKPLOY_URL`, `DOKPLOY_API_KEY`, and staging-only `DOKPLOY_ENVIRONMENT_ID` secrets can be configured once at organization level. See [Repository tooling](docs/repository-tooling.md) for the caller contract, private-registry options, and lifecycle hooks.
|
|
102
|
+
Applications supply only their package, application prefix, port, environment template, and optional product hook. They can provide a custom HTTPS domain, optionally manage a prefixed Cloudflare-proxied record for origins that reject direct traffic, or let Dokploy generate an HTTP `sslip.io` address. The shared `DOKPLOY_URL`, `DOKPLOY_API_KEY`, and staging-only `DOKPLOY_ENVIRONMENT_ID` secrets can be configured once at organization level. See [Repository tooling](https://github.com/richardsolomou/ras-stack/blob/main/docs/repository-tooling.md) for the caller contract, private-registry options, and lifecycle hooks.
|
|
107
103
|
|
|
108
104
|
## Guides 📚
|
|
109
105
|
|
|
110
|
-
| Guide
|
|
111
|
-
|
|
|
112
|
-
| [Application primitives](docs/application-primitives.md) | Authentication, request security, databases, realtime clients, email, uploads, and stateful development resources |
|
|
113
|
-
| [Repository tooling](docs/repository-tooling.md) | TypeScript and Oxlint configuration, generated policy, GitHub Actions, previews, releases, and production runtime composition |
|
|
114
|
-
| [PostHog integration](docs/posthog.md) | Browser/server setup, identity and session correlation, ingest proxying, shutdown, coverage declarations, and source-map responsibility |
|
|
115
|
-
| [Full-stack example](docs/full-stack-example.md) | The `workspace:*` integration contract, local development, production container, and two-browser journey |
|
|
116
|
-
| [Production operations](docs/production-reference-operations.md) | Migration, backup/restore, rollback, configuration, proxy, shutdown, and supply-chain boundaries |
|
|
106
|
+
| Guide | What it covers |
|
|
107
|
+
| ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
108
|
+
| [Application primitives](https://github.com/richardsolomou/ras-stack/blob/main/docs/application-primitives.md) | Authentication, request security, databases, realtime clients, email, uploads, and stateful development resources |
|
|
109
|
+
| [Repository tooling](https://github.com/richardsolomou/ras-stack/blob/main/docs/repository-tooling.md) | TypeScript and Oxlint configuration, generated policy, GitHub Actions, previews, releases, and production runtime composition |
|
|
110
|
+
| [PostHog integration](https://github.com/richardsolomou/ras-stack/blob/main/docs/posthog.md) | Browser/server setup, identity and session correlation, ingest proxying, shutdown, coverage declarations, and source-map responsibility |
|
|
111
|
+
| [Full-stack example](https://github.com/richardsolomou/ras-stack/blob/main/docs/full-stack-example.md) | The `workspace:*` integration contract, local development, production container, and two-browser journey |
|
|
112
|
+
| [Production operations](https://github.com/richardsolomou/ras-stack/blob/main/docs/production-reference-operations.md) | Migration, backup/restore, rollback, configuration, proxy, shutdown, and supply-chain boundaries |
|
|
117
113
|
|
|
118
114
|
## Development 🛠️
|
|
119
115
|
|
|
@@ -124,8 +120,8 @@ just install
|
|
|
124
120
|
just check
|
|
125
121
|
```
|
|
126
122
|
|
|
127
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for release instructions. Report vulnerabilities privately as described in [SECURITY.md](SECURITY.md).
|
|
123
|
+
See [CONTRIBUTING.md](https://github.com/richardsolomou/ras-stack/blob/main/CONTRIBUTING.md) for release instructions. Report vulnerabilities privately as described in [SECURITY.md](https://github.com/richardsolomou/ras-stack/blob/main/SECURITY.md).
|
|
128
124
|
|
|
129
125
|
## License
|
|
130
126
|
|
|
131
|
-
[
|
|
127
|
+
[MIT](https://github.com/richardsolomou/ras-stack/blob/main/packages/ras-stack/LICENSE).
|
package/dist/create/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export async function runCreateCli(arguments_) {
|
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
11
|
const destination = path.resolve(positional[0]);
|
|
12
|
-
const source =
|
|
12
|
+
const source = await starterSource();
|
|
13
13
|
await assertSource(source);
|
|
14
14
|
await assertEmptyDestination(destination);
|
|
15
15
|
if (dryRun) {
|
|
@@ -31,10 +31,24 @@ export async function runCreateCli(arguments_) {
|
|
|
31
31
|
const packageManifest = JSON.parse(await readFile(path.resolve(import.meta.dirname, '../../package.json'), 'utf8'));
|
|
32
32
|
manifest.name = packageName(path.basename(destination));
|
|
33
33
|
manifest.dependencies['ras-stack'] = `^${packageManifest.version}`;
|
|
34
|
-
manifest.scripts.build = manifest.scripts.build.replaceAll('node ../../dist/cli.js', 'ras');
|
|
34
|
+
manifest.scripts.build = manifest.scripts.build.replaceAll('node ../../packages/ras-stack/dist/cli.js', 'ras');
|
|
35
35
|
await writeFile(packageFile, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
36
36
|
console.log(destination);
|
|
37
37
|
}
|
|
38
|
+
async function starterSource() {
|
|
39
|
+
const bundled = path.resolve(import.meta.dirname, 'template');
|
|
40
|
+
try {
|
|
41
|
+
await assertSource(bundled);
|
|
42
|
+
return bundled;
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error.code !== 'ENOENT')
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
const workspace = path.resolve(import.meta.dirname, '../../../../examples/full-stack');
|
|
49
|
+
await assertSource(workspace);
|
|
50
|
+
return workspace;
|
|
51
|
+
}
|
|
38
52
|
async function materializeTemplate(directory, template, output) {
|
|
39
53
|
const source = path.join(directory, template);
|
|
40
54
|
await copyFile(source, path.join(directory, output));
|
package/dist/create/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC9F,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAoB;IACrD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IAC/C,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAA;IAC5E,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC1D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;QACpB,OAAM;IACR,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC,CAAA;IAChD,MAAM,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/create/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { copyFile, cp, mkdir, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport async function runCreateCli(arguments_: string[]) {\n const dryRun = arguments_.includes('--dry-run')\n const positional = arguments_.filter((argument) => argument !== '--dry-run')\n if (positional.length !== 1) {\n console.error('usage: ras create <directory> [--dry-run]')\n process.exitCode = 2\n return\n }\n const destination = path.resolve(positional[0]!)\n const source = await starterSource()\n await assertSource(source)\n await assertEmptyDestination(destination)\n if (dryRun) {\n console.log(destination)\n return\n }\n await mkdir(destination, { recursive: true })\n await cp(source, destination, {\n recursive: true,\n filter: (entry) => !excluded(path.relative(source, entry)),\n })\n await materializeTemplate(destination, 'gitignore.template', '.gitignore')\n await materializeTemplate(destination, 'dockerignore.template', '.dockerignore')\n await materializeTemplate(destination, 'pnpm-workspace.template.yaml', 'pnpm-workspace.yaml')\n await copyFile(path.join(destination, 'Dockerfile.standalone'), path.join(destination, 'Dockerfile'))\n await rm(path.join(destination, 'Dockerfile.standalone'))\n const packageFile = path.join(destination, 'package.json')\n const manifest = JSON.parse(await readFile(packageFile, 'utf8')) as {\n name: string\n dependencies: Record<string, string>\n scripts: Record<string, string>\n }\n const packageManifest = JSON.parse(await readFile(path.resolve(import.meta.dirname, '../../package.json'), 'utf8')) as { version: string }\n manifest.name = packageName(path.basename(destination))\n manifest.dependencies['ras-stack'] = `^${packageManifest.version}`\n manifest.scripts.build = manifest.scripts.build!.replaceAll('node ../../packages/ras-stack/dist/cli.js', 'ras')\n await writeFile(packageFile, `${JSON.stringify(manifest, null, 2)}\\n`)\n console.log(destination)\n}\n\nasync function starterSource() {\n const bundled = path.resolve(import.meta.dirname, 'template')\n try {\n await assertSource(bundled)\n return bundled\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n const workspace = path.resolve(import.meta.dirname, '../../../../examples/full-stack')\n await assertSource(workspace)\n return workspace\n}\n\nasync function materializeTemplate(directory: string, template: string, output: string) {\n const source = path.join(directory, template)\n await copyFile(source, path.join(directory, output))\n await rm(source)\n}\n\nfunction excluded(relative: string) {\n const [root] = relative.split(path.sep)\n return ['.output', '.data', 'node_modules', 'test-results'].includes(root ?? '')\n}\n\nasync function assertSource(source: string) {\n if (!(await stat(path.join(source, 'package.json'))).isFile()) throw new Error('The packaged full-stack starter is missing')\n}\n\nasync function assertEmptyDestination(destination: string) {\n try {\n const info = await stat(destination)\n if (!info.isDirectory() || (await readdir(destination)).length > 0)\n throw new Error(`Destination must be an empty directory: ${destination}`)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n}\n\nfunction packageName(name: string) {\n const normalized = name\n .toLowerCase()\n .replaceAll(/[^a-z\\d._-]/g, '-')\n .replaceAll(/^-+|-+$/g, '')\n return normalized || 'ras-stack-app'\n}\n"]}
|
|
@@ -5,22 +5,22 @@ WORKDIR /app
|
|
|
5
5
|
RUN apk add --no-cache python3 make g++
|
|
6
6
|
RUN corepack enable && corepack install --global pnpm@11.15.0
|
|
7
7
|
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
|
8
|
+
COPY packages/ras-stack/package.json ./packages/ras-stack/package.json
|
|
9
|
+
COPY packages/create-ras-app/package.json ./packages/create-ras-app/package.json
|
|
10
|
+
COPY apps/web/package.json ./apps/web/package.json
|
|
8
11
|
COPY examples/full-stack/package.json ./examples/full-stack/package.json
|
|
9
12
|
RUN pnpm fetch --frozen-lockfile
|
|
10
|
-
COPY
|
|
11
|
-
COPY dist ./dist
|
|
12
|
-
COPY src ./src
|
|
13
|
-
COPY scripts ./scripts
|
|
14
|
-
COPY tsconfig.json tsconfig.build.json LICENSE README.md ./
|
|
13
|
+
COPY packages/ras-stack ./packages/ras-stack
|
|
15
14
|
COPY examples/full-stack ./examples/full-stack
|
|
16
15
|
RUN pnpm install --offline --frozen-lockfile
|
|
17
|
-
RUN pnpm build && pnpm --filter @ras-stack/example-full-stack build
|
|
16
|
+
RUN pnpm --filter ras-stack build && pnpm --filter @ras-stack/example-full-stack build
|
|
18
17
|
|
|
19
18
|
FROM ${RUNTIME_BINARIES_IMAGE} AS runtime-binaries
|
|
20
19
|
|
|
21
20
|
FROM node:24-alpine
|
|
22
21
|
WORKDIR /app
|
|
23
|
-
RUN apk
|
|
22
|
+
RUN apk upgrade --no-cache \
|
|
23
|
+
&& apk add --no-cache tini \
|
|
24
24
|
&& rm -rf /usr/local/lib/node_modules/corepack /usr/local/lib/node_modules/npm /opt/yarn-v1.22.22 \
|
|
25
25
|
&& rm -f /usr/local/bin/corepack /usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/yarn /usr/local/bin/yarnpkg \
|
|
26
26
|
&& mkdir -p /data \
|
|
@@ -29,7 +29,7 @@ COPY --from=build --chown=node:node /app/examples/full-stack/.output ./.output
|
|
|
29
29
|
COPY --from=runtime-binaries /usr/local/bin/centrifugo /usr/local/bin/centrifugo
|
|
30
30
|
COPY --from=runtime-binaries /usr/local/bin/caddy /usr/local/bin/caddy
|
|
31
31
|
COPY --chown=node:node examples/full-stack/centrifugo.json ./centrifugo.json
|
|
32
|
-
COPY --chown=node:node LICENSE ./
|
|
32
|
+
COPY --chown=node:node packages/ras-stack/LICENSE ./
|
|
33
33
|
ENV NODE_ENV=production DATA_DIR=/data TRUST_PROXY=false CENTRIFUGO_CONFIG=/app/centrifugo.json CENTRIFUGO_API_URL=http://127.0.0.1:8100/api CENTRIFUGO_HTTP_SERVER_PORT=8100
|
|
34
34
|
EXPOSE 3100
|
|
35
35
|
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s --retries=3 CMD wget -q --spider http://127.0.0.1:3100/api/ready || exit 1
|
|
@@ -12,7 +12,8 @@ FROM ${RUNTIME_BINARIES_IMAGE} AS runtime-binaries
|
|
|
12
12
|
|
|
13
13
|
FROM node:24-alpine
|
|
14
14
|
WORKDIR /app
|
|
15
|
-
RUN apk
|
|
15
|
+
RUN apk upgrade --no-cache \
|
|
16
|
+
&& apk add --no-cache tini \
|
|
16
17
|
&& rm -rf /usr/local/lib/node_modules/corepack /usr/local/lib/node_modules/npm /opt/yarn-v1.22.22 \
|
|
17
18
|
&& rm -f /usr/local/bin/corepack /usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/yarn /usr/local/bin/yarnpkg \
|
|
18
19
|
&& mkdir -p /data \
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"build": "vite build && node ../../dist/cli.js assets sync && esbuild scripts/containerRuntime.ts scripts/database.ts --bundle --platform=node --format=esm --target=node24 --external:better-sqlite3 --outdir=.output/server --out-extension:.js=.mjs --log-level=warning && node ../../dist/cli.js assets check",
|
|
6
|
+
"build": "vite build && node ../../packages/ras-stack/dist/cli.js assets sync && esbuild scripts/containerRuntime.ts scripts/database.ts --bundle --platform=node --format=esm --target=node24 --external:better-sqlite3 --outdir=.output/server --out-extension:.js=.mjs --log-level=warning && node ../../packages/ras-stack/dist/cli.js assets check",
|
|
7
7
|
"dev": "vite dev",
|
|
8
8
|
"format": "oxfmt --write .",
|
|
9
9
|
"format:check": "oxfmt --check .",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@tanstack/react-start": "^1.168.32",
|
|
30
30
|
"better-auth": "1.7.1",
|
|
31
31
|
"better-sqlite3": "12.11.1",
|
|
32
|
-
"centrifuge": "5.7.
|
|
32
|
+
"centrifuge": "5.7.1",
|
|
33
33
|
"drizzle-orm": "0.45.2",
|
|
34
34
|
"nodemailer": "^9.0.3",
|
|
35
35
|
"posthog-js": "^1.414.0",
|
|
@@ -49,8 +49,9 @@
|
|
|
49
49
|
"@vitejs/plugin-react": "^6.0.5",
|
|
50
50
|
"esbuild": "0.28.2",
|
|
51
51
|
"nitro": "3.0.260610-beta",
|
|
52
|
-
"oxfmt": "^0.
|
|
52
|
+
"oxfmt": "^0.63.0",
|
|
53
53
|
"oxlint": "^1.74.0",
|
|
54
|
+
"oxlint-tsgolint": "^7.0.2001",
|
|
54
55
|
"typescript": "^7.0.2",
|
|
55
56
|
"vite": "8.2.1",
|
|
56
57
|
"vitest": "^4.1.10"
|
package/dist/policy/index.js
CHANGED
|
@@ -20,13 +20,30 @@ const dependabotPolicy = {
|
|
|
20
20
|
directory: '/',
|
|
21
21
|
schedule: { interval: 'weekly' },
|
|
22
22
|
cooldown: { 'default-days': 7 },
|
|
23
|
-
|
|
23
|
+
allow: [
|
|
24
|
+
{
|
|
25
|
+
'dependency-name': '*',
|
|
26
|
+
'update-types': ['version-update:semver-minor', 'version-update:semver-patch'],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
groups: {
|
|
30
|
+
'patch-updates': {
|
|
31
|
+
'applies-to': 'version-updates',
|
|
32
|
+
patterns: ['*'],
|
|
33
|
+
'update-types': ['patch'],
|
|
34
|
+
},
|
|
35
|
+
'minor-updates': {
|
|
36
|
+
'applies-to': 'version-updates',
|
|
37
|
+
patterns: ['*'],
|
|
38
|
+
'update-types': ['minor'],
|
|
39
|
+
},
|
|
40
|
+
},
|
|
24
41
|
},
|
|
25
42
|
{
|
|
26
43
|
'package-ecosystem': 'github-actions',
|
|
27
44
|
directory: '/',
|
|
28
45
|
schedule: { interval: 'weekly' },
|
|
29
|
-
cooldown: { 'default-days': 7 },
|
|
46
|
+
cooldown: { 'default-days': 7, exclude: ['richardsolomou/ras-stack*'] },
|
|
30
47
|
},
|
|
31
48
|
],
|
|
32
49
|
};
|
package/dist/policy/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { parseDocument, stringify } from 'yaml'\n\nconst changesetsPolicy = {\n $schema: 'https://unpkg.com/@changesets/config@3.1.2/schema.json',\n changelog: '@changesets/cli/changelog',\n commit: false,\n fixed: [],\n linked: [],\n access: 'public',\n baseBranch: 'main',\n updateInternalDependencies: 'patch',\n ignore: [],\n}\n\nconst dependabotPolicy = {\n version: 2,\n updates: [\n {\n 'package-ecosystem': 'npm',\n directory: '/',\n schedule: { interval: 'weekly' },\n cooldown: { 'default-days': 7 },\n groups: { 'javascript-dependencies': { patterns: ['*'] } },\n },\n {\n 'package-ecosystem': 'github-actions',\n directory: '/',\n schedule: { interval: 'weekly' },\n cooldown: { 'default-days': 7 },\n },\n ],\n}\n\ntype PolicySelection = boolean | { overrides?: Record<string, unknown> }\n\nexport type RepositoryPolicy = {\n changesets?: PolicySelection\n dependabot?: PolicySelection\n pnpm?: false | { minimumReleaseAge?: number }\n}\n\nexport async function syncRepositoryPolicy(root: string, mode: 'check' | 'write') {\n const config = repositoryPolicy(await readFile(join(root, 'ras-stack.policy.json'), 'utf8'))\n const files = await renderedPolicyFiles(root, config)\n const compared = await Promise.all(\n [...files].map(async ([path, expected]) => {\n const absolute = join(root, path)\n const actual = await readFile(absolute, 'utf8').catch(() => undefined)\n if (actual === expected) return undefined\n if (mode === 'write') {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, expected)\n }\n return path\n }),\n )\n return compared.filter((path) => path !== undefined)\n}\n\nexport async function checkRepositoryPolicy(root: string) {\n const files = await syncRepositoryPolicy(root, 'check')\n return files.map((path) => `policy drift: ${path}`)\n}\n\nexport async function renderedPolicyFiles(root: string, config: RepositoryPolicy) {\n const files = new Map<string, string>()\n if (config.changesets) {\n files.set('.changeset/config.json', `${JSON.stringify(selectedPolicy(changesetsPolicy, config.changesets), null, 2)}\\n`)\n }\n if (config.dependabot) {\n files.set('.github/dependabot.yml', stringify(selectedPolicy(dependabotPolicy, config.dependabot), { lineWidth: 0, singleQuote: true }))\n }\n if (config.pnpm) {\n const path = join(root, 'pnpm-workspace.yaml')\n const document = parseDocument(await readFile(path, 'utf8').catch(() => ''))\n document.set('minimumReleaseAge', config.pnpm.minimumReleaseAge ?? 10_080)\n files.set('pnpm-workspace.yaml', document.toString({ lineWidth: 0 }))\n }\n return files\n}\n\nfunction repositoryPolicy(source: string): RepositoryPolicy {\n const value = JSON.parse(source) as unknown\n if (!plainObject(value)) throw new Error('ras-stack.policy.json must contain an object')\n for (const name of ['changesets', 'dependabot'] as const) validateSelection(name, value[name])\n const pnpm = value.pnpm\n if (pnpm !== undefined && pnpm !== false) {\n if (!plainObject(pnpm)) throw new Error('pnpm policy must be false or an object')\n const age = pnpm.minimumReleaseAge\n if (age !== undefined && (typeof age !== 'number' || !Number.isInteger(age) || age < 0)) {\n throw new Error('pnpm.minimumReleaseAge must be a non-negative integer')\n }\n }\n return value\n}\n\nfunction validateSelection(name: string, value: unknown) {\n if (value === undefined || typeof value === 'boolean') return\n if (!plainObject(value) || (value.overrides !== undefined && !plainObject(value.overrides))) {\n throw new Error(`${name} policy must be a boolean or an object with overrides`)\n }\n}\n\nfunction selectedPolicy(base: Record<string, unknown>, selection: Exclude<PolicySelection, false>) {\n return selection === true ? base : deepMerge(base, selection.overrides ?? {})\n}\n\nfunction deepMerge(base: Record<string, unknown>, overrides: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n [...new Set([...Object.keys(base), ...Object.keys(overrides)])].map((key) => {\n const left = base[key]\n const right = overrides[key]\n return [key, plainObject(left) && plainObject(right) ? deepMerge(left, right) : right === undefined ? left : right]\n }),\n )\n}\n\nfunction plainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { parseDocument, stringify } from 'yaml'\n\nconst changesetsPolicy = {\n $schema: 'https://unpkg.com/@changesets/config@3.1.2/schema.json',\n changelog: '@changesets/cli/changelog',\n commit: false,\n fixed: [],\n linked: [],\n access: 'public',\n baseBranch: 'main',\n updateInternalDependencies: 'patch',\n ignore: [],\n}\n\nconst dependabotPolicy = {\n version: 2,\n updates: [\n {\n 'package-ecosystem': 'npm',\n directory: '/',\n schedule: { interval: 'weekly' },\n cooldown: { 'default-days': 7 },\n allow: [\n {\n 'dependency-name': '*',\n 'update-types': ['version-update:semver-minor', 'version-update:semver-patch'],\n },\n ],\n groups: {\n 'patch-updates': {\n 'applies-to': 'version-updates',\n patterns: ['*'],\n 'update-types': ['patch'],\n },\n 'minor-updates': {\n 'applies-to': 'version-updates',\n patterns: ['*'],\n 'update-types': ['minor'],\n },\n },\n },\n {\n 'package-ecosystem': 'github-actions',\n directory: '/',\n schedule: { interval: 'weekly' },\n cooldown: { 'default-days': 7, exclude: ['richardsolomou/ras-stack*'] },\n },\n ],\n}\n\ntype PolicySelection = boolean | { overrides?: Record<string, unknown> }\n\nexport type RepositoryPolicy = {\n changesets?: PolicySelection\n dependabot?: PolicySelection\n pnpm?: false | { minimumReleaseAge?: number }\n}\n\nexport async function syncRepositoryPolicy(root: string, mode: 'check' | 'write') {\n const config = repositoryPolicy(await readFile(join(root, 'ras-stack.policy.json'), 'utf8'))\n const files = await renderedPolicyFiles(root, config)\n const compared = await Promise.all(\n [...files].map(async ([path, expected]) => {\n const absolute = join(root, path)\n const actual = await readFile(absolute, 'utf8').catch(() => undefined)\n if (actual === expected) return undefined\n if (mode === 'write') {\n await mkdir(dirname(absolute), { recursive: true })\n await writeFile(absolute, expected)\n }\n return path\n }),\n )\n return compared.filter((path) => path !== undefined)\n}\n\nexport async function checkRepositoryPolicy(root: string) {\n const files = await syncRepositoryPolicy(root, 'check')\n return files.map((path) => `policy drift: ${path}`)\n}\n\nexport async function renderedPolicyFiles(root: string, config: RepositoryPolicy) {\n const files = new Map<string, string>()\n if (config.changesets) {\n files.set('.changeset/config.json', `${JSON.stringify(selectedPolicy(changesetsPolicy, config.changesets), null, 2)}\\n`)\n }\n if (config.dependabot) {\n files.set('.github/dependabot.yml', stringify(selectedPolicy(dependabotPolicy, config.dependabot), { lineWidth: 0, singleQuote: true }))\n }\n if (config.pnpm) {\n const path = join(root, 'pnpm-workspace.yaml')\n const document = parseDocument(await readFile(path, 'utf8').catch(() => ''))\n document.set('minimumReleaseAge', config.pnpm.minimumReleaseAge ?? 10_080)\n files.set('pnpm-workspace.yaml', document.toString({ lineWidth: 0 }))\n }\n return files\n}\n\nfunction repositoryPolicy(source: string): RepositoryPolicy {\n const value = JSON.parse(source) as unknown\n if (!plainObject(value)) throw new Error('ras-stack.policy.json must contain an object')\n for (const name of ['changesets', 'dependabot'] as const) validateSelection(name, value[name])\n const pnpm = value.pnpm\n if (pnpm !== undefined && pnpm !== false) {\n if (!plainObject(pnpm)) throw new Error('pnpm policy must be false or an object')\n const age = pnpm.minimumReleaseAge\n if (age !== undefined && (typeof age !== 'number' || !Number.isInteger(age) || age < 0)) {\n throw new Error('pnpm.minimumReleaseAge must be a non-negative integer')\n }\n }\n return value\n}\n\nfunction validateSelection(name: string, value: unknown) {\n if (value === undefined || typeof value === 'boolean') return\n if (!plainObject(value) || (value.overrides !== undefined && !plainObject(value.overrides))) {\n throw new Error(`${name} policy must be a boolean or an object with overrides`)\n }\n}\n\nfunction selectedPolicy(base: Record<string, unknown>, selection: Exclude<PolicySelection, false>) {\n return selection === true ? base : deepMerge(base, selection.overrides ?? {})\n}\n\nfunction deepMerge(base: Record<string, unknown>, overrides: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(\n [...new Set([...Object.keys(base), ...Object.keys(overrides)])].map((key) => {\n const left = base[key]\n const right = overrides[key]\n return [key, plainObject(left) && plainObject(right) ? deepMerge(left, right) : right === undefined ? left : right]\n }),\n )\n}\n\nfunction plainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n"]}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -53,5 +53,7 @@ export type CaddyRealtimeProxyOptions = {
|
|
|
53
53
|
appPort?: number;
|
|
54
54
|
realtimePort?: number;
|
|
55
55
|
websocketPath?: string;
|
|
56
|
+
/** Compress responses with zstd and gzip. On unless turned off: Caddy already skips upgrades and incompressible content. */
|
|
57
|
+
encode?: boolean;
|
|
56
58
|
};
|
|
57
59
|
export declare function caddyRealtimeProxy(options?: CaddyRealtimeProxyOptions): string;
|
package/dist/runtime/index.js
CHANGED
|
@@ -207,7 +207,7 @@ export function caddyRealtimeProxy(options = {}) {
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
:${publicPort} {
|
|
210
|
-
\troute {
|
|
210
|
+
${options.encode === false ? '' : '\tencode zstd gzip\n'}\troute {
|
|
211
211
|
\t\t@foreignWebSocketOrigin \`{path}.startsWith('${websocketPath}') && {http.request.header.Origin} != '' && {http.request.header.Origin} != 'http://' + {http.request.hostport} && {http.request.header.Origin} != 'https://' + {http.request.hostport}\`
|
|
212
212
|
\t\trespond @foreignWebSocketOrigin 403
|
|
213
213
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, type ChildProcess } from 'node:child_process'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport { runRealtimeDev, type RealtimeDevOptions } from './dev.js'\n\nexport type RuntimeProcess = {\n name: string\n command: string\n args?: readonly string[]\n cwd?: string\n env?: NodeJS.ProcessEnv\n}\n\ntype SignalSource = Pick<NodeJS.Process, 'off' | 'once'>\ntype SpawnProcess = (process: RuntimeProcess) => ChildProcess\n\nexport type SupervisorOptions = {\n shutdownTimeoutMs?: number\n signalSource?: SignalSource\n spawn?: SpawnProcess\n}\n\nexport async function superviseProcesses(processes: readonly RuntimeProcess[], options: SupervisorOptions = {}) {\n return runSupervisor(processes, options)\n}\n\nasync function runSupervisor(processes: readonly RuntimeProcess[], options: SupervisorOptions, shutdownOrder?: readonly string[]) {\n if (processes.length === 0) throw new Error('at least one runtime process is required')\n const names = new Set<string>()\n for (const process of processes) {\n if (!process.name.trim()) throw new Error('runtime process names must not be empty')\n if (!process.command.trim()) throw new Error(`runtime process ${process.name} must have a command`)\n if (names.has(process.name)) throw new Error(`duplicate runtime process name: ${process.name}`)\n names.add(process.name)\n }\n\n const signalSource = options.signalSource ?? process\n const shutdownTimeoutMs = options.shutdownTimeoutMs ?? 10_000\n if (!Number.isSafeInteger(shutdownTimeoutMs) || shutdownTimeoutMs < 0) {\n throw new Error('shutdownTimeoutMs must be a non-negative integer')\n }\n const spawnProcess =\n options.spawn ??\n ((specification: RuntimeProcess) =>\n spawn(specification.command, [...(specification.args ?? [])], {\n cwd: specification.cwd,\n env: specification.env ?? process.env,\n stdio: 'inherit',\n }))\n const children = new Map<ChildProcess, string>()\n const exits = new Map<ChildProcess, Promise<void>>()\n let settled = false\n let phasedShutdown = false\n let expectedExit: ChildProcess | undefined\n let resolveResult!: (value: number) => void\n const result = new Promise<number>((resolve) => {\n resolveResult = resolve\n })\n\n const finishImmediately = async (status: number) => {\n if (settled) return\n settled = true\n signalSource.off('SIGINT', onSignal)\n signalSource.off('SIGTERM', onSignal)\n await stopChildren([...children.keys()], shutdownTimeoutMs)\n resolveResult(status)\n }\n const finishInPhases = async () => {\n if (settled || phasedShutdown) return\n phasedShutdown = true\n signalSource.off('SIGINT', onSignal)\n signalSource.off('SIGTERM', onSignal)\n const deadline = Date.now() + shutdownTimeoutMs\n for (const name of shutdownOrder ?? []) {\n if (settled) return\n const child = [...children].find(([, childName]) => childName === name)?.[0]\n if (!child || !running(child)) continue\n expectedExit = child\n child.kill('SIGTERM')\n // oxlint-disable-next-line no-await-in-loop -- Shutdown phases must remain dependency-ordered.\n const exited = await beforeDeadline(exits.get(child)!, Math.max(0, deadline - Date.now()))\n expectedExit = undefined\n if (settled) return\n if (!exited) {\n settled = true\n for (const runningChild of children.keys()) if (running(runningChild)) runningChild.kill('SIGKILL')\n resolveResult(0)\n return\n }\n }\n settled = true\n resolveResult(0)\n }\n const onSignal = () => {\n if (shutdownOrder) void finishInPhases()\n else void finishImmediately(0)\n }\n signalSource.once('SIGINT', onSignal)\n signalSource.once('SIGTERM', onSignal)\n\n try {\n for (const specification of processes) {\n const child = spawnProcess(specification)\n children.set(child, specification.name)\n let resolveExit!: () => void\n exits.set(\n child,\n new Promise<void>((resolve) => {\n resolveExit = resolve\n }),\n )\n child.once('error', () => void finishImmediately(1))\n child.once('exit', (code) => {\n resolveExit()\n if (!phasedShutdown || child !== expectedExit) void finishImmediately(code && code > 0 ? code : 1)\n })\n }\n } catch (error) {\n await finishImmediately(1)\n throw error\n }\n return result\n}\n\nasync function beforeDeadline(exited: Promise<void>, timeoutMs: number) {\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<false>((resolve) => {\n timer = setTimeout(() => resolve(false), timeoutMs)\n })\n const result = await Promise.race([exited.then(() => true as const), timeout])\n if (timer) clearTimeout(timer)\n return result\n}\n\nfunction running(child: ChildProcess) {\n return child.exitCode === null && child.signalCode === null\n}\n\nasync function stopChildren(children: ChildProcess[], timeoutMs: number) {\n const active = children.filter(running)\n if (active.length === 0) return\n const exited = Promise.all(active.map((child) => new Promise<void>((resolve) => child.once('exit', () => resolve())))).then(\n () => 'exited' as const,\n )\n for (const child of active) child.kill('SIGTERM')\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<'timeout'>((resolve) => {\n timer = setTimeout(() => resolve('timeout'), timeoutMs)\n })\n const outcome = await Promise.race([exited, timeout])\n if (timer) clearTimeout(timer)\n if (outcome === 'timeout') {\n for (const child of active) if (running(child)) child.kill('SIGKILL')\n }\n}\n\nexport type CentrifugoEnvironmentOptions = {\n apiKey: string\n clientTokenSecret?: string\n subscriptionTokenSecret?: string\n allowedOrigins?: string\n redisUrl?: string\n}\n\nexport type RealtimeStackOptions = {\n app: Omit<RuntimeProcess, 'name'>\n centrifugo: {\n command?: string\n configPath: string\n cwd?: string\n env?: NodeJS.ProcessEnv\n environment: CentrifugoEnvironmentOptions\n }\n caddy: {\n command?: string\n configPath: string\n cwd?: string\n env?: NodeJS.ProcessEnv\n proxy?: CaddyRealtimeProxyOptions\n runtime?: CaddyRuntimeEnvironmentOptions\n }\n supervisor?: SupervisorOptions\n}\n\nexport async function runRealtimeStack(options: RealtimeStackOptions) {\n const configPath = absolutePath(options.caddy.configPath, 'caddy.configPath')\n const centrifugoConfigPath = absolutePath(options.centrifugo.configPath, 'centrifugo.configPath')\n await mkdir(path.dirname(configPath), { recursive: true })\n await writeFile(configPath, caddyRealtimeProxy(options.caddy.proxy), 'utf8')\n return runSupervisor(\n [\n { name: 'app', ...options.app },\n {\n name: 'realtime',\n command: options.centrifugo.command ?? 'centrifugo',\n args: [`--config=${centrifugoConfigPath}`],\n ...(options.centrifugo.cwd ? { cwd: options.centrifugo.cwd } : {}),\n env: { ...options.centrifugo.env, ...centrifugoEnvironment(options.centrifugo.environment) },\n },\n {\n name: 'proxy',\n command: options.caddy.command ?? 'caddy',\n args: ['run', '--config', configPath, '--adapter', 'caddyfile'],\n ...(options.caddy.cwd ? { cwd: options.caddy.cwd } : {}),\n env: { ...options.caddy.env, ...caddyRuntimeEnvironment(options.caddy.runtime) },\n },\n ],\n options.supervisor ?? {},\n ['proxy', 'app', 'realtime'],\n )\n}\n\nexport function centrifugoEnvironment(options: CentrifugoEnvironmentOptions): NodeJS.ProcessEnv {\n const apiKey = requiredValue(options.apiKey, 'apiKey')\n const clientTokenSecret = options.clientTokenSecret?.trim()\n const subscriptionTokenSecret = options.subscriptionTokenSecret?.trim()\n return {\n CENTRIFUGO_HTTP_API_KEY: apiKey,\n CENTRIFUGO_CLIENT_ALLOWED_ORIGINS: options.allowedOrigins?.trim() || '*',\n CENTRIFUGO_HTTP_SERVER_ADDRESS: '127.0.0.1',\n CENTRIFUGO_HEALTH_ENABLED: 'true',\n ...(clientTokenSecret ? { CENTRIFUGO_CLIENT_TOKEN_HMAC_SECRET_KEY: clientTokenSecret } : {}),\n ...(subscriptionTokenSecret\n ? {\n CENTRIFUGO_CLIENT_SUBSCRIPTION_TOKEN_ENABLED: 'true',\n CENTRIFUGO_CLIENT_SUBSCRIPTION_TOKEN_HMAC_SECRET_KEY: subscriptionTokenSecret,\n }\n : {}),\n ...(options.redisUrl\n ? { CENTRIFUGO_ENGINE_TYPE: 'redis', CENTRIFUGO_ENGINE_REDIS_ADDRESS: requiredValue(options.redisUrl, 'redisUrl') }\n : {}),\n }\n}\n\nexport type CaddyRuntimeEnvironmentOptions = { configHome?: string; dataHome?: string }\n\nexport function caddyRuntimeEnvironment(options: CaddyRuntimeEnvironmentOptions = {}): NodeJS.ProcessEnv {\n const configHome = absolutePath(options.configHome ?? '/tmp/caddy-config', 'configHome')\n const dataHome = absolutePath(options.dataHome ?? '/tmp/caddy-data', 'dataHome')\n return { XDG_CONFIG_HOME: configHome, XDG_DATA_HOME: dataHome }\n}\n\nexport type CaddyRealtimeProxyOptions = { publicPort?: number; appPort?: number; realtimePort?: number; websocketPath?: string }\n\nexport function caddyRealtimeProxy(options: CaddyRealtimeProxyOptions = {}) {\n const publicPort = port(options.publicPort ?? 3000, 'publicPort')\n const appPort = port(options.appPort ?? 3001, 'appPort')\n const realtimePort = port(options.realtimePort ?? 8000, 'realtimePort')\n const websocketPath = options.websocketPath ?? '/connection/'\n if (!/^\\/[A-Za-z0-9._~/-]+\\/$/.test(websocketPath) || websocketPath.includes('//')) {\n throw new Error('websocketPath must be a normalized absolute directory path')\n }\n return `{\n\\tservers {\n\\t\\ttrusted_proxies static private_ranges\n\\t\\ttrusted_proxies_strict\n\\t}\n}\n\n:${publicPort} {\n\\troute {\n\\t\\t@foreignWebSocketOrigin \\`{path}.startsWith('${websocketPath}') && {http.request.header.Origin} != '' && {http.request.header.Origin} != 'http://' + {http.request.hostport} && {http.request.header.Origin} != 'https://' + {http.request.hostport}\\`\n\\t\\trespond @foreignWebSocketOrigin 403\n\n\\t\\thandle ${websocketPath}* {\n\\t\\t\\treverse_proxy 127.0.0.1:${realtimePort}\n\\t\\t}\n\n\\t\\thandle {\n\\t\\t\\treverse_proxy 127.0.0.1:${appPort}\n\\t\\t}\n\\t}\n}\n`\n}\n\nfunction requiredValue(value: string, name: string) {\n const normalized = value.trim()\n if (!normalized) throw new Error(`${name} is required`)\n return normalized\n}\n\nfunction port(value: number, name: string) {\n if (!Number.isInteger(value) || value < 1 || value > 65_535) throw new Error(`${name} must be a valid TCP port`)\n return value\n}\n\nfunction absolutePath(value: string, name: string) {\n if (!path.isAbsolute(value)) throw new Error(`${name} must be an absolute path`)\n return value\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, type ChildProcess } from 'node:child_process'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport { runRealtimeDev, type RealtimeDevOptions } from './dev.js'\n\nexport type RuntimeProcess = {\n name: string\n command: string\n args?: readonly string[]\n cwd?: string\n env?: NodeJS.ProcessEnv\n}\n\ntype SignalSource = Pick<NodeJS.Process, 'off' | 'once'>\ntype SpawnProcess = (process: RuntimeProcess) => ChildProcess\n\nexport type SupervisorOptions = {\n shutdownTimeoutMs?: number\n signalSource?: SignalSource\n spawn?: SpawnProcess\n}\n\nexport async function superviseProcesses(processes: readonly RuntimeProcess[], options: SupervisorOptions = {}) {\n return runSupervisor(processes, options)\n}\n\nasync function runSupervisor(processes: readonly RuntimeProcess[], options: SupervisorOptions, shutdownOrder?: readonly string[]) {\n if (processes.length === 0) throw new Error('at least one runtime process is required')\n const names = new Set<string>()\n for (const process of processes) {\n if (!process.name.trim()) throw new Error('runtime process names must not be empty')\n if (!process.command.trim()) throw new Error(`runtime process ${process.name} must have a command`)\n if (names.has(process.name)) throw new Error(`duplicate runtime process name: ${process.name}`)\n names.add(process.name)\n }\n\n const signalSource = options.signalSource ?? process\n const shutdownTimeoutMs = options.shutdownTimeoutMs ?? 10_000\n if (!Number.isSafeInteger(shutdownTimeoutMs) || shutdownTimeoutMs < 0) {\n throw new Error('shutdownTimeoutMs must be a non-negative integer')\n }\n const spawnProcess =\n options.spawn ??\n ((specification: RuntimeProcess) =>\n spawn(specification.command, [...(specification.args ?? [])], {\n cwd: specification.cwd,\n env: specification.env ?? process.env,\n stdio: 'inherit',\n }))\n const children = new Map<ChildProcess, string>()\n const exits = new Map<ChildProcess, Promise<void>>()\n let settled = false\n let phasedShutdown = false\n let expectedExit: ChildProcess | undefined\n let resolveResult!: (value: number) => void\n const result = new Promise<number>((resolve) => {\n resolveResult = resolve\n })\n\n const finishImmediately = async (status: number) => {\n if (settled) return\n settled = true\n signalSource.off('SIGINT', onSignal)\n signalSource.off('SIGTERM', onSignal)\n await stopChildren([...children.keys()], shutdownTimeoutMs)\n resolveResult(status)\n }\n const finishInPhases = async () => {\n if (settled || phasedShutdown) return\n phasedShutdown = true\n signalSource.off('SIGINT', onSignal)\n signalSource.off('SIGTERM', onSignal)\n const deadline = Date.now() + shutdownTimeoutMs\n for (const name of shutdownOrder ?? []) {\n if (settled) return\n const child = [...children].find(([, childName]) => childName === name)?.[0]\n if (!child || !running(child)) continue\n expectedExit = child\n child.kill('SIGTERM')\n // oxlint-disable-next-line no-await-in-loop -- Shutdown phases must remain dependency-ordered.\n const exited = await beforeDeadline(exits.get(child)!, Math.max(0, deadline - Date.now()))\n expectedExit = undefined\n if (settled) return\n if (!exited) {\n settled = true\n for (const runningChild of children.keys()) if (running(runningChild)) runningChild.kill('SIGKILL')\n resolveResult(0)\n return\n }\n }\n settled = true\n resolveResult(0)\n }\n const onSignal = () => {\n if (shutdownOrder) void finishInPhases()\n else void finishImmediately(0)\n }\n signalSource.once('SIGINT', onSignal)\n signalSource.once('SIGTERM', onSignal)\n\n try {\n for (const specification of processes) {\n const child = spawnProcess(specification)\n children.set(child, specification.name)\n let resolveExit!: () => void\n exits.set(\n child,\n new Promise<void>((resolve) => {\n resolveExit = resolve\n }),\n )\n child.once('error', () => void finishImmediately(1))\n child.once('exit', (code) => {\n resolveExit()\n if (!phasedShutdown || child !== expectedExit) void finishImmediately(code && code > 0 ? code : 1)\n })\n }\n } catch (error) {\n await finishImmediately(1)\n throw error\n }\n return result\n}\n\nasync function beforeDeadline(exited: Promise<void>, timeoutMs: number) {\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<false>((resolve) => {\n timer = setTimeout(() => resolve(false), timeoutMs)\n })\n const result = await Promise.race([exited.then(() => true as const), timeout])\n if (timer) clearTimeout(timer)\n return result\n}\n\nfunction running(child: ChildProcess) {\n return child.exitCode === null && child.signalCode === null\n}\n\nasync function stopChildren(children: ChildProcess[], timeoutMs: number) {\n const active = children.filter(running)\n if (active.length === 0) return\n const exited = Promise.all(active.map((child) => new Promise<void>((resolve) => child.once('exit', () => resolve())))).then(\n () => 'exited' as const,\n )\n for (const child of active) child.kill('SIGTERM')\n let timer: ReturnType<typeof setTimeout> | undefined\n const timeout = new Promise<'timeout'>((resolve) => {\n timer = setTimeout(() => resolve('timeout'), timeoutMs)\n })\n const outcome = await Promise.race([exited, timeout])\n if (timer) clearTimeout(timer)\n if (outcome === 'timeout') {\n for (const child of active) if (running(child)) child.kill('SIGKILL')\n }\n}\n\nexport type CentrifugoEnvironmentOptions = {\n apiKey: string\n clientTokenSecret?: string\n subscriptionTokenSecret?: string\n allowedOrigins?: string\n redisUrl?: string\n}\n\nexport type RealtimeStackOptions = {\n app: Omit<RuntimeProcess, 'name'>\n centrifugo: {\n command?: string\n configPath: string\n cwd?: string\n env?: NodeJS.ProcessEnv\n environment: CentrifugoEnvironmentOptions\n }\n caddy: {\n command?: string\n configPath: string\n cwd?: string\n env?: NodeJS.ProcessEnv\n proxy?: CaddyRealtimeProxyOptions\n runtime?: CaddyRuntimeEnvironmentOptions\n }\n supervisor?: SupervisorOptions\n}\n\nexport async function runRealtimeStack(options: RealtimeStackOptions) {\n const configPath = absolutePath(options.caddy.configPath, 'caddy.configPath')\n const centrifugoConfigPath = absolutePath(options.centrifugo.configPath, 'centrifugo.configPath')\n await mkdir(path.dirname(configPath), { recursive: true })\n await writeFile(configPath, caddyRealtimeProxy(options.caddy.proxy), 'utf8')\n return runSupervisor(\n [\n { name: 'app', ...options.app },\n {\n name: 'realtime',\n command: options.centrifugo.command ?? 'centrifugo',\n args: [`--config=${centrifugoConfigPath}`],\n ...(options.centrifugo.cwd ? { cwd: options.centrifugo.cwd } : {}),\n env: { ...options.centrifugo.env, ...centrifugoEnvironment(options.centrifugo.environment) },\n },\n {\n name: 'proxy',\n command: options.caddy.command ?? 'caddy',\n args: ['run', '--config', configPath, '--adapter', 'caddyfile'],\n ...(options.caddy.cwd ? { cwd: options.caddy.cwd } : {}),\n env: { ...options.caddy.env, ...caddyRuntimeEnvironment(options.caddy.runtime) },\n },\n ],\n options.supervisor ?? {},\n ['proxy', 'app', 'realtime'],\n )\n}\n\nexport function centrifugoEnvironment(options: CentrifugoEnvironmentOptions): NodeJS.ProcessEnv {\n const apiKey = requiredValue(options.apiKey, 'apiKey')\n const clientTokenSecret = options.clientTokenSecret?.trim()\n const subscriptionTokenSecret = options.subscriptionTokenSecret?.trim()\n return {\n CENTRIFUGO_HTTP_API_KEY: apiKey,\n CENTRIFUGO_CLIENT_ALLOWED_ORIGINS: options.allowedOrigins?.trim() || '*',\n CENTRIFUGO_HTTP_SERVER_ADDRESS: '127.0.0.1',\n CENTRIFUGO_HEALTH_ENABLED: 'true',\n ...(clientTokenSecret ? { CENTRIFUGO_CLIENT_TOKEN_HMAC_SECRET_KEY: clientTokenSecret } : {}),\n ...(subscriptionTokenSecret\n ? {\n CENTRIFUGO_CLIENT_SUBSCRIPTION_TOKEN_ENABLED: 'true',\n CENTRIFUGO_CLIENT_SUBSCRIPTION_TOKEN_HMAC_SECRET_KEY: subscriptionTokenSecret,\n }\n : {}),\n ...(options.redisUrl\n ? { CENTRIFUGO_ENGINE_TYPE: 'redis', CENTRIFUGO_ENGINE_REDIS_ADDRESS: requiredValue(options.redisUrl, 'redisUrl') }\n : {}),\n }\n}\n\nexport type CaddyRuntimeEnvironmentOptions = { configHome?: string; dataHome?: string }\n\nexport function caddyRuntimeEnvironment(options: CaddyRuntimeEnvironmentOptions = {}): NodeJS.ProcessEnv {\n const configHome = absolutePath(options.configHome ?? '/tmp/caddy-config', 'configHome')\n const dataHome = absolutePath(options.dataHome ?? '/tmp/caddy-data', 'dataHome')\n return { XDG_CONFIG_HOME: configHome, XDG_DATA_HOME: dataHome }\n}\n\nexport type CaddyRealtimeProxyOptions = {\n publicPort?: number\n appPort?: number\n realtimePort?: number\n websocketPath?: string\n /** Compress responses with zstd and gzip. On unless turned off: Caddy already skips upgrades and incompressible content. */\n encode?: boolean\n}\n\nexport function caddyRealtimeProxy(options: CaddyRealtimeProxyOptions = {}) {\n const publicPort = port(options.publicPort ?? 3000, 'publicPort')\n const appPort = port(options.appPort ?? 3001, 'appPort')\n const realtimePort = port(options.realtimePort ?? 8000, 'realtimePort')\n const websocketPath = options.websocketPath ?? '/connection/'\n if (!/^\\/[A-Za-z0-9._~/-]+\\/$/.test(websocketPath) || websocketPath.includes('//')) {\n throw new Error('websocketPath must be a normalized absolute directory path')\n }\n return `{\n\\tservers {\n\\t\\ttrusted_proxies static private_ranges\n\\t\\ttrusted_proxies_strict\n\\t}\n}\n\n:${publicPort} {\n${options.encode === false ? '' : '\\tencode zstd gzip\\n'}\\troute {\n\\t\\t@foreignWebSocketOrigin \\`{path}.startsWith('${websocketPath}') && {http.request.header.Origin} != '' && {http.request.header.Origin} != 'http://' + {http.request.hostport} && {http.request.header.Origin} != 'https://' + {http.request.hostport}\\`\n\\t\\trespond @foreignWebSocketOrigin 403\n\n\\t\\thandle ${websocketPath}* {\n\\t\\t\\treverse_proxy 127.0.0.1:${realtimePort}\n\\t\\t}\n\n\\t\\thandle {\n\\t\\t\\treverse_proxy 127.0.0.1:${appPort}\n\\t\\t}\n\\t}\n}\n`\n}\n\nfunction requiredValue(value: string, name: string) {\n const normalized = value.trim()\n if (!normalized) throw new Error(`${name} is required`)\n return normalized\n}\n\nfunction port(value: number, name: string) {\n if (!Number.isInteger(value) || value < 1 || value > 65_535) throw new Error(`${name} must be a valid TCP port`)\n return value\n}\n\nfunction absolutePath(value: string, name: string) {\n if (!path.isAbsolute(value)) throw new Error(`${name} must be an absolute path`)\n return value\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ras-stack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.1",
|
|
4
4
|
"description": "Composable full-stack primitives shared across Richard Solomou's applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authentication",
|
|
@@ -9,20 +9,20 @@
|
|
|
9
9
|
"tanstack",
|
|
10
10
|
"tus"
|
|
11
11
|
],
|
|
12
|
-
"homepage": "https://github.com/richardsolomou/ras-stack#readme",
|
|
12
|
+
"homepage": "https://github.com/richardsolomou/ras-stack/tree/main/packages/ras-stack#readme",
|
|
13
13
|
"bugs": "https://github.com/richardsolomou/ras-stack/issues",
|
|
14
|
-
"license": "
|
|
14
|
+
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
16
16
|
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/richardsolomou/ras-stack.git"
|
|
17
|
+
"url": "git+https://github.com/richardsolomou/ras-stack.git",
|
|
18
|
+
"directory": "packages/ras-stack"
|
|
18
19
|
},
|
|
19
20
|
"bin": {
|
|
20
21
|
"ras": "./dist/cli.js"
|
|
21
22
|
},
|
|
22
23
|
"files": [
|
|
23
24
|
"dist",
|
|
24
|
-
"config"
|
|
25
|
-
"examples/full-stack"
|
|
25
|
+
"config"
|
|
26
26
|
],
|
|
27
27
|
"type": "module",
|
|
28
28
|
"sideEffects": false,
|
|
@@ -154,12 +154,10 @@
|
|
|
154
154
|
"yaml": "^2.8.2"
|
|
155
155
|
},
|
|
156
156
|
"devDependencies": {
|
|
157
|
-
"@changesets/cli": "^2.31.1",
|
|
158
157
|
"@opentelemetry/api-logs": "^0.221.0",
|
|
159
158
|
"@opentelemetry/exporter-logs-otlp-http": "^0.221.0",
|
|
160
159
|
"@opentelemetry/resources": "^2.10.0",
|
|
161
160
|
"@opentelemetry/sdk-logs": "^0.221.0",
|
|
162
|
-
"@playwright/test": "1.62.1",
|
|
163
161
|
"@posthog/react": "^1.10.3",
|
|
164
162
|
"@tanstack/react-query": "^5.101.4",
|
|
165
163
|
"@tanstack/react-start": "^1.168.32",
|
|
@@ -170,10 +168,10 @@
|
|
|
170
168
|
"@types/react-test-renderer": "19.1.0",
|
|
171
169
|
"@vitest/coverage-v8": "^4.1.10",
|
|
172
170
|
"better-sqlite3": "12.11.1",
|
|
173
|
-
"centrifuge": "5.7.
|
|
171
|
+
"centrifuge": "5.7.1",
|
|
174
172
|
"drizzle-orm": "0.45.2",
|
|
175
173
|
"nodemailer": "^9.0.3",
|
|
176
|
-
"oxfmt": "^0.
|
|
174
|
+
"oxfmt": "^0.63.0",
|
|
177
175
|
"oxlint": "^1.74.0",
|
|
178
176
|
"oxlint-tsgolint": "^7.0.2001",
|
|
179
177
|
"postgres": "3.4.9",
|
|
@@ -258,7 +256,7 @@
|
|
|
258
256
|
"node": ">=24 <25"
|
|
259
257
|
},
|
|
260
258
|
"scripts": {
|
|
261
|
-
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
259
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && node scripts/copyStarter.mjs",
|
|
262
260
|
"config:check": "tsc -p test/config-consumer/tsconfig.json && tsc -p test/config-consumer/tsconfig-bundler.json && tsc -p test/config-consumer/tsconfig-node-bundler.json && tsc -p test/config-consumer/tsconfig-library.json && oxlint --config config/oxlint/application.json --print-config > /dev/null && oxlint --config config/oxlint/tanstack.json --print-config > /dev/null",
|
|
263
261
|
"typecheck": "tsc --noEmit",
|
|
264
262
|
"lint": "oxlint --type-aware --deny-warnings .",
|
|
@@ -267,7 +265,6 @@
|
|
|
267
265
|
"test": "vitest run --config vitest.config.ts",
|
|
268
266
|
"package:check": "node scripts/checkPackedPackage.mjs",
|
|
269
267
|
"peer:floor": "node scripts/checkPeerFloor.mjs",
|
|
270
|
-
"check": "pnpm format:check && pnpm lint && pnpm config:check && pnpm typecheck && pnpm test && pnpm build && pnpm package:check
|
|
271
|
-
"version-packages": "changeset version"
|
|
268
|
+
"check": "pnpm format:check && pnpm lint && pnpm config:check && pnpm typecheck && pnpm test && pnpm build && pnpm package:check"
|
|
272
269
|
}
|
|
273
270
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|