toiljs 0.0.115 → 0.0.117
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/CHANGELOG.md +10 -0
- package/README.md +16 -7
- package/TYPESCRIPT_LAW.md +1946 -2073
- package/build/backend/.tsbuildinfo +1 -1
- package/build/cli/.tsbuildinfo +1 -1
- package/build/cli/index.js +2375 -258
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/dev/devtools.js +1 -1
- package/build/client/dev/error-overlay.js +1 -1
- package/build/client/routing/mount.js +1 -1
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/auth-emails.js +7 -3
- package/build/compiler/emails.js +1 -1
- package/build/compiler/index.d.ts +1 -0
- package/build/compiler/index.js +25 -4
- package/build/compiler/pages.js +2 -3
- package/build/compiler/prerender.d.ts +3 -8
- package/build/compiler/prerender.js +88 -127
- package/build/compiler/ssg.js +3 -4
- package/build/compiler/template-build.js +3 -4
- package/build/compiler/toil-docs.generated.js +6 -5
- package/build/compiler/vite.js +3 -6
- package/build/devserver/.tsbuildinfo +1 -1
- package/build/devserver/db/database.js +7 -3
- package/build/devserver/db/types.js +1 -1
- package/build/devserver/production.js +4 -3
- package/build/devserver/runtime/crypto.d.ts +1 -1
- package/build/io/.tsbuildinfo +1 -1
- package/build/logger/.tsbuildinfo +1 -1
- package/build/shared/.tsbuildinfo +1 -1
- package/examples/basic/client/routes/analytics.tsx +7 -5
- package/examples/basic/server/tsconfig.json +1 -3
- package/package.json +45 -44
- package/presets/no-uint8array-tostring.js +120 -153
- package/presets/oxlint.d.ts +5 -0
- package/presets/oxlint.js +224 -0
- package/server/runtime/tsconfig.json +1 -3
- package/tsconfig.json +2 -11
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
- package/.github/ISSUE_TEMPLATE/config.yml +0 -8
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -43
- package/.github/changelog-config.json +0 -45
- package/.github/dependabot.yml +0 -27
- package/.github/workflows/ci.yml +0 -222
- package/.vscode/settings.json +0 -10
- package/docs/README.md +0 -107
- package/docs/auth/README.md +0 -104
- package/docs/auth/configuration.md +0 -105
- package/docs/auth/emails.md +0 -92
- package/docs/auth/extending.md +0 -202
- package/docs/auth/how-it-works.md +0 -138
- package/docs/auth/usage.md +0 -188
- package/docs/backend/README.md +0 -143
- package/docs/backend/data.md +0 -351
- package/docs/backend/rest.md +0 -402
- package/docs/backend/rpc.md +0 -226
- package/docs/background/README.md +0 -114
- package/docs/background/daemons.md +0 -276
- package/docs/background/derive.md +0 -179
- package/docs/cli/README.md +0 -379
- package/docs/concepts/ai-guide.md +0 -132
- package/docs/concepts/config.md +0 -416
- package/docs/concepts/decorators.md +0 -127
- package/docs/concepts/security.md +0 -108
- package/docs/concepts/tiers.md +0 -166
- package/docs/concepts/types.md +0 -216
- package/docs/database/README.md +0 -143
- package/docs/database/capacity.md +0 -350
- package/docs/database/counters.md +0 -174
- package/docs/database/documents.md +0 -277
- package/docs/database/events.md +0 -307
- package/docs/database/membership.md +0 -246
- package/docs/database/setup.md +0 -155
- package/docs/database/unique.md +0 -216
- package/docs/database/views.md +0 -246
- package/docs/frontend/README.md +0 -104
- package/docs/frontend/components.md +0 -286
- package/docs/frontend/data-fetching.md +0 -260
- package/docs/frontend/images.md +0 -148
- package/docs/frontend/metadata.md +0 -344
- package/docs/frontend/navigation.md +0 -296
- package/docs/frontend/rendering.md +0 -236
- package/docs/frontend/routing.md +0 -346
- package/docs/frontend/scripts.md +0 -118
- package/docs/frontend/search.md +0 -191
- package/docs/frontend/styling.md +0 -147
- package/docs/frontend/toil-global.md +0 -216
- package/docs/getting-started/README.md +0 -81
- package/docs/getting-started/create-project.md +0 -131
- package/docs/getting-started/deploy.md +0 -101
- package/docs/getting-started/first-app.md +0 -215
- package/docs/getting-started/installation.md +0 -124
- package/docs/getting-started/migrating.md +0 -125
- package/docs/getting-started/project-structure.md +0 -163
- package/docs/introduction/README.md +0 -66
- package/docs/introduction/design-principles.md +0 -81
- package/docs/introduction/distributed.md +0 -91
- package/docs/introduction/how-it-works.md +0 -121
- package/docs/introduction/hyperscale.md +0 -70
- package/docs/introduction/modern-stack.md +0 -85
- package/docs/introduction/vs-other-frameworks.md +0 -64
- package/docs/introduction/why-toil.md +0 -99
- package/docs/llms.txt +0 -95
- package/docs/realtime/README.md +0 -102
- package/docs/realtime/channels.md +0 -211
- package/docs/realtime/streams.md +0 -369
- package/docs/services/README.md +0 -60
- package/docs/services/analytics.md +0 -279
- package/docs/services/caching.md +0 -175
- package/docs/services/cookies.md +0 -235
- package/docs/services/crypto.md +0 -209
- package/docs/services/email.md +0 -289
- package/docs/services/environment.md +0 -141
- package/docs/services/ratelimit.md +0 -174
- package/docs/services/time.md +0 -85
- package/eslint.config.js +0 -57
- package/examples/basic/client/routes/docs/[...slug].tsx +0 -12
- package/presets/eslint.js +0 -88
- package/src/backend/index.ts +0 -204
- package/src/cli/configure.ts +0 -363
- package/src/cli/create.ts +0 -924
- package/src/cli/db.ts +0 -158
- package/src/cli/diagnostics.ts +0 -665
- package/src/cli/doctor.ts +0 -982
- package/src/cli/features.ts +0 -170
- package/src/cli/index.ts +0 -326
- package/src/cli/notify.ts +0 -120
- package/src/cli/proc.ts +0 -56
- package/src/cli/ui.ts +0 -169
- package/src/cli/update.ts +0 -248
- package/src/cli/updates.ts +0 -92
- package/src/cli/validate.ts +0 -31
- package/src/cli/version-check.ts +0 -125
- package/src/client/auth.ts +0 -869
- package/src/client/channel/channel.ts +0 -146
- package/src/client/components/Form.tsx +0 -65
- package/src/client/components/Image.tsx +0 -160
- package/src/client/components/Script.tsx +0 -113
- package/src/client/components/Slot.tsx +0 -21
- package/src/client/dev/devtools.tsx +0 -1089
- package/src/client/dev/error-overlay.tsx +0 -225
- package/src/client/errors.ts +0 -11
- package/src/client/head/head.ts +0 -182
- package/src/client/head/metadata.ts +0 -110
- package/src/client/index.ts +0 -130
- package/src/client/navigation/Link.tsx +0 -108
- package/src/client/navigation/NavLink.tsx +0 -86
- package/src/client/navigation/navigation.ts +0 -235
- package/src/client/navigation/prefetch.ts +0 -169
- package/src/client/navigation/scroll.ts +0 -53
- package/src/client/routing/Router.tsx +0 -216
- package/src/client/routing/action.ts +0 -122
- package/src/client/routing/error-boundary.tsx +0 -43
- package/src/client/routing/hooks.ts +0 -140
- package/src/client/routing/lazy.ts +0 -77
- package/src/client/routing/loader.ts +0 -381
- package/src/client/routing/match.ts +0 -47
- package/src/client/routing/mount.tsx +0 -90
- package/src/client/routing/params-context.ts +0 -10
- package/src/client/routing/slot-context.ts +0 -7
- package/src/client/rpc.ts +0 -97
- package/src/client/search/search.ts +0 -189
- package/src/client/search/use-page-search.ts +0 -73
- package/src/client/ssr/markers.tsx +0 -172
- package/src/client/stream/client.ts +0 -237
- package/src/client/types.ts +0 -73
- package/src/compiler/auth-emails.ts +0 -312
- package/src/compiler/config.ts +0 -369
- package/src/compiler/docs.ts +0 -127
- package/src/compiler/email-preview.ts +0 -314
- package/src/compiler/emails.ts +0 -404
- package/src/compiler/fonts.ts +0 -89
- package/src/compiler/generate.ts +0 -471
- package/src/compiler/image-blur.ts +0 -42
- package/src/compiler/image-report.ts +0 -88
- package/src/compiler/index.ts +0 -1362
- package/src/compiler/pages.ts +0 -49
- package/src/compiler/plugin.ts +0 -391
- package/src/compiler/prerender.ts +0 -263
- package/src/compiler/routes.ts +0 -170
- package/src/compiler/seo.ts +0 -415
- package/src/compiler/sri.ts +0 -144
- package/src/compiler/ssg.ts +0 -177
- package/src/compiler/ssr-codegen.ts +0 -85
- package/src/compiler/template-build.ts +0 -676
- package/src/compiler/template.ts +0 -262
- package/src/compiler/toil-docs.generated.ts +0 -77
- package/src/compiler/vite.ts +0 -245
- package/src/devserver/analytics/index.ts +0 -317
- package/src/devserver/config/dotenv.ts +0 -102
- package/src/devserver/config/env.ts +0 -30
- package/src/devserver/config/ratelimit.ts +0 -123
- package/src/devserver/daemon/catalog.ts +0 -120
- package/src/devserver/daemon/cron.ts +0 -87
- package/src/devserver/daemon/host.ts +0 -134
- package/src/devserver/daemon/index.ts +0 -369
- package/src/devserver/daemon/runtime.ts +0 -48
- package/src/devserver/db/catalog.ts +0 -109
- package/src/devserver/db/database.ts +0 -1834
- package/src/devserver/db/derives.ts +0 -121
- package/src/devserver/db/index.ts +0 -20
- package/src/devserver/db/routeKinds.ts +0 -191
- package/src/devserver/db/types.ts +0 -168
- package/src/devserver/email/caps.ts +0 -0
- package/src/devserver/email/config.ts +0 -141
- package/src/devserver/email/console.ts +0 -348
- package/src/devserver/email/index.ts +0 -155
- package/src/devserver/email/providers.ts +0 -131
- package/src/devserver/email/status.ts +0 -23
- package/src/devserver/email/validate.ts +0 -37
- package/src/devserver/email/wire.ts +0 -55
- package/src/devserver/http/cache.ts +0 -0
- package/src/devserver/http/envelope.ts +0 -157
- package/src/devserver/http/proxy.ts +0 -172
- package/src/devserver/http/runtime.ts +0 -387
- package/src/devserver/index.ts +0 -43
- package/src/devserver/production-ipc.ts +0 -63
- package/src/devserver/production-worker.ts +0 -83
- package/src/devserver/production.ts +0 -718
- package/src/devserver/runtime/crypto.ts +0 -587
- package/src/devserver/runtime/host.ts +0 -427
- package/src/devserver/runtime/module.ts +0 -442
- package/src/devserver/server.ts +0 -251
- package/src/devserver/ssr.ts +0 -208
- package/src/devserver/stream/catalog.ts +0 -106
- package/src/devserver/stream/host.ts +0 -42
- package/src/devserver/stream/index.ts +0 -301
- package/src/devserver/stream/manager.ts +0 -167
- package/src/devserver/stream/router.ts +0 -101
- package/src/devserver/stream/wire.ts +0 -58
- package/src/devserver/stream/ws.ts +0 -78
- package/src/devserver/wasm/sections.ts +0 -59
- package/src/devserver/wasm/surface.ts +0 -115
- package/src/io/FastMap.ts +0 -151
- package/src/io/FastSet.ts +0 -113
- package/src/io/codec.ts +0 -362
- package/src/io/index.ts +0 -10
- package/src/io/lengths.ts +0 -14
- package/src/io/types.ts +0 -19
- package/src/logger/index.ts +0 -22
- package/src/shared/index.ts +0 -46
- package/test/analytics-dev.test.ts +0 -113
- package/test/assembly/aspect-shim.ts +0 -33
- package/test/assembly/cookie.spec.ts +0 -303
- package/test/assembly/example.spec.ts +0 -22
- package/test/assembly/ssr.spec.ts +0 -95
- package/test/assembly.test.ts +0 -59
- package/test/auth-emails.test.ts +0 -118
- package/test/built-ssr.test.ts +0 -148
- package/test/channel.test.ts +0 -21
- package/test/config-host-port.test.ts +0 -59
- package/test/configure.test.ts +0 -94
- package/test/daemon-build.test.ts +0 -278
- package/test/daemon-catalog.test.ts +0 -349
- package/test/daemon-emulation.test.ts +0 -256
- package/test/db.test.ts +0 -0
- package/test/devserver-database.test.ts +0 -1102
- package/test/devserver-email.test.ts +0 -306
- package/test/devserver-pqauth.test.ts +0 -93
- package/test/devserver-secrets.test.ts +0 -63
- package/test/devserver.test.ts +0 -259
- package/test/doctor.test.ts +0 -298
- package/test/dom/Image.test.tsx +0 -144
- package/test/dom/Link.test.tsx +0 -67
- package/test/dom/NavLink.test.tsx +0 -37
- package/test/dom/Script.test.tsx +0 -48
- package/test/dom/action.test.tsx +0 -146
- package/test/dom/error-overlay.test.tsx +0 -44
- package/test/dom/loader.test.tsx +0 -121
- package/test/dom/navigation.test.ts +0 -59
- package/test/dom/revalidate.test.tsx +0 -38
- package/test/dom/route-head.test.tsx +0 -56
- package/test/dom/router-loading.test.tsx +0 -44
- package/test/dom/scroll.test.ts +0 -56
- package/test/dom/slot.test.tsx +0 -131
- package/test/dom/use-metadata.test.tsx +0 -58
- package/test/dom/view-transitions.test.tsx +0 -53
- package/test/dynamic-routing.test.ts +0 -132
- package/test/email-console.test.ts +0 -86
- package/test/email-preview.test.ts +0 -73
- package/test/emails.test.ts +0 -58
- package/test/errors.test.ts +0 -21
- package/test/example-guestbook.test.ts +0 -123
- package/test/features.test.ts +0 -149
- package/test/fixtures/bignum-wire/spec.ts +0 -25
- package/test/fixtures/daemon-app.ts +0 -65
- package/test/fixtures/stream-echo.ts +0 -26
- package/test/fixtures/stream-gate.ts +0 -28
- package/test/fixtures/stream-trap.ts +0 -18
- package/test/fixtures/stream-typed.ts +0 -41
- package/test/fonts.test.ts +0 -28
- package/test/global-setup.ts +0 -17
- package/test/head.test.ts +0 -42
- package/test/image-blur.test.ts +0 -50
- package/test/io.test.ts +0 -117
- package/test/metadata.test.ts +0 -40
- package/test/navlink.test.ts +0 -28
- package/test/pages.test.ts +0 -105
- package/test/placeholder.test.ts +0 -9
- package/test/pqauth-e2e.test.ts +0 -216
- package/test/pqauth-email.test.ts +0 -801
- package/test/prerender.test.ts +0 -116
- package/test/prettier-plugin.test.ts +0 -46
- package/test/routes.test.ts +0 -76
- package/test/rpc-bignum-wire.test.ts +0 -164
- package/test/rpc-dispatch.test.ts +0 -132
- package/test/rpc-kinds.test.ts +0 -18
- package/test/rpc.test.ts +0 -66
- package/test/search.test.ts +0 -114
- package/test/seo.test.ts +0 -175
- package/test/slot-layouts.test.ts +0 -69
- package/test/sri.test.ts +0 -129
- package/test/ssg.test.ts +0 -36
- package/test/ssr-hydration.test.tsx +0 -122
- package/test/ssr-render.test.ts +0 -197
- package/test/ssr-template.test.tsx +0 -482
- package/test/stream-emulation.test.ts +0 -479
- package/test/ui.test.ts +0 -40
- package/test/update.test.ts +0 -58
- package/test/validate.test.ts +0 -42
- package/test/version-check.test.ts +0 -130
- package/tests/data-parity/generated-parity.ts +0 -99
- package/tests/data-parity/parity.ts +0 -80
- package/tests/data-parity/spec.ts +0 -46
package/src/cli/features.ts
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure description of toiljs's optional client styling features, a CSS preprocessor and Tailwind ,
|
|
3
|
-
* shared by `create` (scaffold) and `configure` (toggle on existing projects). Dependency-light
|
|
4
|
-
* (no node IO) so it can be unit-tested; the file writes and package-manager calls live in the
|
|
5
|
-
* commands. Preprocessor and Tailwind are independent: Tailwind lives in its own `.css` entry so
|
|
6
|
-
* it never passes through (and breaks on) a preprocessor's `@import` resolution.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/** Supported CSS preprocessor (`css` = none). */
|
|
10
|
-
export type Preprocessor = 'css' | 'sass' | 'less' | 'stylus';
|
|
11
|
-
|
|
12
|
-
/** The two independently-toggleable styling features of a project. */
|
|
13
|
-
export interface StyleFeatures {
|
|
14
|
-
readonly preprocessor: Preprocessor;
|
|
15
|
-
readonly tailwind: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const PREPROCESSORS: readonly Preprocessor[] = ['css', 'sass', 'less', 'stylus'];
|
|
19
|
-
|
|
20
|
-
/** Main stylesheet extension for each preprocessor. */
|
|
21
|
-
export const STYLE_EXT: Record<Preprocessor, string> = {
|
|
22
|
-
css: 'css',
|
|
23
|
-
sass: 'scss',
|
|
24
|
-
less: 'less',
|
|
25
|
-
stylus: 'styl',
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/** npm package that enables each preprocessor in Vite (plain CSS needs none). */
|
|
29
|
-
export const PREPROCESSOR_PKG: Record<Preprocessor, string | null> = {
|
|
30
|
-
css: null,
|
|
31
|
-
sass: 'sass',
|
|
32
|
-
less: 'less',
|
|
33
|
-
stylus: 'stylus',
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/** Tailwind v4 packages. The framework auto-wires the Vite plugin when `@tailwindcss/vite` resolves. */
|
|
37
|
-
export const TAILWIND_PKGS: readonly string[] = ['tailwindcss', '@tailwindcss/vite'];
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Pinned versions for every package these features may install. `@tailwindcss/vite` must be
|
|
41
|
-
* `>= 4.3.0`: earlier 4.x releases cap their `vite` peer at `^7`, so they ERESOLVE against the
|
|
42
|
-
* Vite 8 toiljs ships (the "Tailwind broken on install" error). Keep both Tailwind pins in lockstep.
|
|
43
|
-
*/
|
|
44
|
-
export const PKG_VERSION: Record<string, string> = {
|
|
45
|
-
sass: '^1.83.0',
|
|
46
|
-
less: '^4.2.1',
|
|
47
|
-
stylus: '^0.64.0',
|
|
48
|
-
tailwindcss: '^4.3.0',
|
|
49
|
-
'@tailwindcss/vite': '^4.3.0',
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/** Dedicated Tailwind entry (kept `.css` so no preprocessor touches its `@import`). */
|
|
53
|
-
export const TAILWIND_ENTRY = 'styles/tailwind.css';
|
|
54
|
-
export const TAILWIND_CSS = `@import 'tailwindcss';\n`;
|
|
55
|
-
|
|
56
|
-
/** Path (relative to `client/`) of the main stylesheet for a preprocessor. */
|
|
57
|
-
export function styleEntry(p: Preprocessor): string {
|
|
58
|
-
return `styles/main.${STYLE_EXT[p]}`;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** The preprocessor whose main stylesheet uses `ext` (with or without a leading dot), or null. */
|
|
62
|
-
export function preprocessorForExt(ext: string): Preprocessor | null {
|
|
63
|
-
const e = ext.replace(/^\./, '');
|
|
64
|
-
if (e === 'sass') return 'sass';
|
|
65
|
-
return PREPROCESSORS.find((p) => STYLE_EXT[p] === e) ?? null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Packages required by a feature set (preprocessor package + Tailwind packages). */
|
|
69
|
-
export function requiredPackages(f: StyleFeatures): string[] {
|
|
70
|
-
const pkgs: string[] = [];
|
|
71
|
-
const pp = PREPROCESSOR_PKG[f.preprocessor];
|
|
72
|
-
if (pp) pkgs.push(pp);
|
|
73
|
-
if (f.tailwind) pkgs.push(...TAILWIND_PKGS);
|
|
74
|
-
return pkgs;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Managed packages to add and remove when moving from `from` to `to`. */
|
|
78
|
-
export function packageDiff(
|
|
79
|
-
from: StyleFeatures,
|
|
80
|
-
to: StyleFeatures,
|
|
81
|
-
): { add: string[]; remove: string[] } {
|
|
82
|
-
const want = new Set(requiredPackages(to));
|
|
83
|
-
const had = new Set(requiredPackages(from));
|
|
84
|
-
return {
|
|
85
|
-
add: [...want].filter((p) => !had.has(p)),
|
|
86
|
-
remove: [...had].filter((p) => !want.has(p)),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/** The side-effect style imports for the app entry, Tailwind first so app CSS can override it. */
|
|
91
|
-
export function styleImportLines(f: StyleFeatures): string[] {
|
|
92
|
-
const lines: string[] = [];
|
|
93
|
-
if (f.tailwind) lines.push(`import './${TAILWIND_ENTRY}';`);
|
|
94
|
-
lines.push(`import './${styleEntry(f.preprocessor)}';`);
|
|
95
|
-
return lines;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Rewrites the `./styles/*` side-effect imports in an app entry (`client/toil.tsx`) to match
|
|
100
|
-
* `features`, preserving the rest of the file. Existing style imports are removed and the new
|
|
101
|
-
* block is placed after the `toiljs/routes` import (or the last import, or the top).
|
|
102
|
-
*/
|
|
103
|
-
export function setStyleImports(source: string, f: StyleFeatures): string {
|
|
104
|
-
const stripped = source.replace(
|
|
105
|
-
/^[ \t]*import\s+['"]\.\/styles\/[^'"]+['"];?[ \t]*\r?\n/gm,
|
|
106
|
-
'',
|
|
107
|
-
);
|
|
108
|
-
const block = styleImportLines(f).join('\n') + '\n';
|
|
109
|
-
|
|
110
|
-
const lines = stripped.split('\n');
|
|
111
|
-
const routesIdx = lines.findIndex((l) => /from\s+['"]toiljs\/routes['"]/.test(l));
|
|
112
|
-
let insertAt: number;
|
|
113
|
-
if (routesIdx !== -1) {
|
|
114
|
-
insertAt = routesIdx + 1;
|
|
115
|
-
} else {
|
|
116
|
-
const lastImport = lines.reduce((acc, l, i) => (/^\s*import\s/.test(l) ? i : acc), -1);
|
|
117
|
-
insertAt = lastImport + 1;
|
|
118
|
-
}
|
|
119
|
-
const head = lines.slice(0, insertAt).join('\n');
|
|
120
|
-
const tail = lines.slice(insertAt).join('\n');
|
|
121
|
-
return `${head}\n\n${block}\n${tail}`.replace(/\n{3,}/g, '\n\n');
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** A `toil.config` source containing `client: { images: <bool> }` (for scaffolding when none exists). */
|
|
125
|
-
export function defaultConfigSource(images: boolean): string {
|
|
126
|
-
return (
|
|
127
|
-
"import { defineConfig } from 'toiljs/compiler';\n\n" +
|
|
128
|
-
'export default defineConfig({\n' +
|
|
129
|
-
' client: {\n' +
|
|
130
|
-
' // Optimize images at build time (resize/compress imported images).\n' +
|
|
131
|
-
` images: ${String(images)},\n` +
|
|
132
|
-
' },\n' +
|
|
133
|
-
'});\n'
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Sets the `client.images` flag in a `toil.config` source, returning the updated source, or `null`
|
|
139
|
-
* if the file's shape isn't recognized (the caller should then fall back to a manual note). Handles
|
|
140
|
-
* an existing `images:` value, an existing `client: {` block, or a bare `defineConfig({ … })`.
|
|
141
|
-
*/
|
|
142
|
-
export function setConfigImages(source: string, enabled: boolean): string | null {
|
|
143
|
-
const value = String(enabled);
|
|
144
|
-
if (/\bimages\s*:\s*(?:true|false)/.test(source)) {
|
|
145
|
-
return source.replace(/\bimages\s*:\s*(?:true|false)/, `images: ${value}`);
|
|
146
|
-
}
|
|
147
|
-
if (/\bclient\s*:\s*\{/.test(source)) {
|
|
148
|
-
return source.replace(/\bclient\s*:\s*\{/, `client: {\n images: ${value},`);
|
|
149
|
-
}
|
|
150
|
-
if (/defineConfig\(\s*\{/.test(source)) {
|
|
151
|
-
return source.replace(
|
|
152
|
-
/defineConfig\(\s*\{/,
|
|
153
|
-
`defineConfig({\n client: { images: ${value} },`,
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** Detects the active preprocessor from a project's combined dependency map. */
|
|
160
|
-
export function detectPreprocessor(deps: Record<string, string>): Preprocessor {
|
|
161
|
-
if ('sass' in deps) return 'sass';
|
|
162
|
-
if ('less' in deps) return 'less';
|
|
163
|
-
if ('stylus' in deps) return 'stylus';
|
|
164
|
-
return 'css';
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/** Whether Tailwind is installed in a project's combined dependency map. */
|
|
168
|
-
export function detectTailwind(deps: Record<string, string>): boolean {
|
|
169
|
-
return '@tailwindcss/vite' in deps || 'tailwindcss' in deps;
|
|
170
|
-
}
|
package/src/cli/index.ts
DELETED
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* toiljs CLI. Routes `create` / `dev` / `build` and wraps them in the toiljs brand banner.
|
|
4
|
-
* The compiler stays presentation-free (imported via the package's own `toiljs/compiler`
|
|
5
|
-
* export); the epic bits, banner, the Clack scaffolding wizard, live here.
|
|
6
|
-
*/
|
|
7
|
-
import { build, dev, start } from 'toiljs/compiler';
|
|
8
|
-
|
|
9
|
-
import { runConfigure } from './configure.js';
|
|
10
|
-
import { runCreate, type Template } from './create.js';
|
|
11
|
-
import { runDb } from './db.js';
|
|
12
|
-
import { runDoctor } from './doctor.js';
|
|
13
|
-
import { notifyIfOutdated } from './notify.js';
|
|
14
|
-
import { runUpdate } from './update.js';
|
|
15
|
-
import { type Preprocessor, PREPROCESSORS } from './features.js';
|
|
16
|
-
import { accent, banner, bold, danger, dim, success, version } from './ui.js';
|
|
17
|
-
|
|
18
|
-
// Node 22+/26 prints an ExperimentalWarning the first time any code touches the
|
|
19
|
-
// built-in `localStorage` global (some browser-oriented deps do when they are
|
|
20
|
-
// evaluated server-side during the dev SSR pass). It is harmless (localStorage
|
|
21
|
-
// works fine in the real browser) but noisy on every `toiljs dev`/`build`, so drop
|
|
22
|
-
// exactly that one warning here, before anything runs. Every other warning still
|
|
23
|
-
// prints. Installed on the CLI process, ahead of the compiler/dev work.
|
|
24
|
-
const __origEmitWarning = process.emitWarning.bind(process) as (...a: unknown[]) => void;
|
|
25
|
-
process.emitWarning = ((warning: unknown, ...rest: unknown[]): void => {
|
|
26
|
-
const msg = typeof warning === 'string' ? warning : (warning as { message?: string })?.message;
|
|
27
|
-
if (typeof msg === 'string' && msg.includes('localStorage is not available')) return;
|
|
28
|
-
__origEmitWarning(warning, ...rest);
|
|
29
|
-
}) as typeof process.emitWarning;
|
|
30
|
-
|
|
31
|
-
interface Flags {
|
|
32
|
-
root?: string;
|
|
33
|
-
port?: number;
|
|
34
|
-
host?: string;
|
|
35
|
-
threads?: number;
|
|
36
|
-
name?: string;
|
|
37
|
-
template?: Template;
|
|
38
|
-
preprocessor?: Preprocessor;
|
|
39
|
-
tailwind?: boolean;
|
|
40
|
-
ai?: boolean;
|
|
41
|
-
images?: boolean;
|
|
42
|
-
install?: boolean;
|
|
43
|
-
git?: boolean;
|
|
44
|
-
pm?: string;
|
|
45
|
-
yes?: boolean;
|
|
46
|
-
json?: boolean;
|
|
47
|
-
fix?: boolean;
|
|
48
|
-
target?: string;
|
|
49
|
-
server?: boolean;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function parseArgs(argv: string[]): Flags {
|
|
53
|
-
const flags: Flags = {};
|
|
54
|
-
for (let i = 0; i < argv.length; i++) {
|
|
55
|
-
const arg = argv[i];
|
|
56
|
-
switch (arg) {
|
|
57
|
-
case '--root':
|
|
58
|
-
flags.root = argv[++i];
|
|
59
|
-
break;
|
|
60
|
-
case '--port': {
|
|
61
|
-
const port = Number(argv[++i]);
|
|
62
|
-
if (!Number.isNaN(port)) flags.port = port;
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
|
-
case '--host':
|
|
66
|
-
flags.host = argv[++i];
|
|
67
|
-
break;
|
|
68
|
-
case '--threads':
|
|
69
|
-
case '--workers': {
|
|
70
|
-
const threads = Number(argv[++i]);
|
|
71
|
-
if (!Number.isNaN(threads)) flags.threads = threads;
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
case '--template':
|
|
75
|
-
case '-t': {
|
|
76
|
-
const t = argv[++i];
|
|
77
|
-
if (t === 'app' || t === 'minimal' || t === 'agent') flags.template = t;
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
case '--pm':
|
|
81
|
-
flags.pm = argv[++i];
|
|
82
|
-
break;
|
|
83
|
-
case '--style': {
|
|
84
|
-
const s = argv[++i];
|
|
85
|
-
if ((PREPROCESSORS as readonly string[]).includes(s))
|
|
86
|
-
flags.preprocessor = s as Preprocessor;
|
|
87
|
-
break;
|
|
88
|
-
}
|
|
89
|
-
case '--tailwind':
|
|
90
|
-
flags.tailwind = true;
|
|
91
|
-
break;
|
|
92
|
-
case '--no-tailwind':
|
|
93
|
-
flags.tailwind = false;
|
|
94
|
-
break;
|
|
95
|
-
case '--ai':
|
|
96
|
-
flags.ai = true;
|
|
97
|
-
break;
|
|
98
|
-
case '--no-ai':
|
|
99
|
-
flags.ai = false;
|
|
100
|
-
break;
|
|
101
|
-
case '--images':
|
|
102
|
-
flags.images = true;
|
|
103
|
-
break;
|
|
104
|
-
case '--no-images':
|
|
105
|
-
flags.images = false;
|
|
106
|
-
break;
|
|
107
|
-
case '--install':
|
|
108
|
-
flags.install = true;
|
|
109
|
-
break;
|
|
110
|
-
case '--no-install':
|
|
111
|
-
flags.install = false;
|
|
112
|
-
break;
|
|
113
|
-
case '--git':
|
|
114
|
-
flags.git = true;
|
|
115
|
-
break;
|
|
116
|
-
case '--no-git':
|
|
117
|
-
flags.git = false;
|
|
118
|
-
break;
|
|
119
|
-
case '-y':
|
|
120
|
-
case '--yes':
|
|
121
|
-
flags.yes = true;
|
|
122
|
-
break;
|
|
123
|
-
case '--json':
|
|
124
|
-
flags.json = true;
|
|
125
|
-
break;
|
|
126
|
-
case '--fix':
|
|
127
|
-
flags.fix = true;
|
|
128
|
-
break;
|
|
129
|
-
case '--target':
|
|
130
|
-
flags.target = argv[++i];
|
|
131
|
-
break;
|
|
132
|
-
case '--server':
|
|
133
|
-
flags.server = true;
|
|
134
|
-
break;
|
|
135
|
-
default:
|
|
136
|
-
if (!arg.startsWith('-') && flags.name === undefined) flags.name = arg;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return flags;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function printHelp(): void {
|
|
143
|
-
const cmd = (name: string, desc: string): string => ` ${accent(name.padEnd(15))}${dim(desc)}`;
|
|
144
|
-
process.stdout.write(
|
|
145
|
-
[
|
|
146
|
-
`${bold('Usage')} ${dim('toiljs')} <command> [options]`,
|
|
147
|
-
'',
|
|
148
|
-
bold('Commands'),
|
|
149
|
-
cmd('create [name]', 'scaffold a new toiljs app'),
|
|
150
|
-
cmd('configure', 'toggle styling features (Sass/Less/Stylus, Tailwind)'),
|
|
151
|
-
cmd('dev', 'start the dev server with HMR'),
|
|
152
|
-
cmd('build', 'build the optimized production bundle'),
|
|
153
|
-
cmd('start', 'self-host the built app (hyper-express / uWS)'),
|
|
154
|
-
cmd('doctor', 'diagnose project setup and dependencies'),
|
|
155
|
-
cmd('update', 'check for and apply dependency updates'),
|
|
156
|
-
cmd('db <action>', 'manage dev DB data (status | reset | export | import)'),
|
|
157
|
-
'',
|
|
158
|
-
bold('Options'),
|
|
159
|
-
cmd('--root <dir>', 'project root (default: current directory)'),
|
|
160
|
-
cmd('--port <n>', 'dev/start: listen port (or PORT env / client.port; default 3000)'),
|
|
161
|
-
cmd('--host <h>', 'dev/start: bind host, e.g. 0.0.0.0 (or HOST env / client.host; default 127.0.0.1)'),
|
|
162
|
-
cmd('--threads <n>', 'start: production HTTP worker count'),
|
|
163
|
-
cmd('-t, --template', 'create: app | minimal | agent'),
|
|
164
|
-
cmd('--style <name>', 'create/configure: css | sass | less | stylus'),
|
|
165
|
-
cmd('--tailwind', 'create/configure: enable Tailwind (--no-tailwind to remove)'),
|
|
166
|
-
cmd('--no-ai', 'create: skip AI assistant files (CLAUDE.md, etc.)'),
|
|
167
|
-
cmd('-y, --yes', 'create: accept defaults (non-interactive)'),
|
|
168
|
-
cmd('--no-install', "create: don't install dependencies"),
|
|
169
|
-
cmd('--server', 'build: build only the server (regenerate shared/server.ts + wasm)'),
|
|
170
|
-
cmd('--json', 'doctor: machine-readable output'),
|
|
171
|
-
cmd('--fix', 'doctor: auto-fix what it can (typed-RPC wiring)'),
|
|
172
|
-
cmd('--target <t>', 'update: latest | minor | patch | newest | greatest'),
|
|
173
|
-
cmd('-v, --version', 'print the toiljs version'),
|
|
174
|
-
'',
|
|
175
|
-
dim(' Every command checks npm for a newer toiljs and warns when outdated.'),
|
|
176
|
-
dim(' Set TOILJS_NO_UPDATE_CHECK=1 to opt out.'),
|
|
177
|
-
'',
|
|
178
|
-
].join('\n') + '\n',
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
async function main(): Promise<void> {
|
|
183
|
-
const [command, ...rest] = process.argv.slice(2);
|
|
184
|
-
|
|
185
|
-
if (command === '--version' || command === '-v') {
|
|
186
|
-
process.stdout.write(version() + '\n');
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const flags = parseArgs(rest);
|
|
191
|
-
|
|
192
|
-
// Every invocation (including `npm run dev` / `npm run build`, which call this CLI)
|
|
193
|
-
// checks that the installed toiljs is the latest release. Warns on stderr, never blocks
|
|
194
|
-
// the command; opt out with TOILJS_NO_UPDATE_CHECK=1.
|
|
195
|
-
await notifyIfOutdated(flags.root);
|
|
196
|
-
|
|
197
|
-
switch (command) {
|
|
198
|
-
case 'create':
|
|
199
|
-
banner();
|
|
200
|
-
await runCreate({
|
|
201
|
-
name: flags.name,
|
|
202
|
-
template: flags.template,
|
|
203
|
-
preprocessor: flags.preprocessor,
|
|
204
|
-
tailwind: flags.tailwind,
|
|
205
|
-
ai: flags.ai,
|
|
206
|
-
images: flags.images,
|
|
207
|
-
install: flags.install,
|
|
208
|
-
git: flags.git,
|
|
209
|
-
pm: flags.pm,
|
|
210
|
-
yes: flags.yes,
|
|
211
|
-
cwd: process.cwd(),
|
|
212
|
-
});
|
|
213
|
-
break;
|
|
214
|
-
|
|
215
|
-
case 'configure':
|
|
216
|
-
banner();
|
|
217
|
-
await runConfigure({
|
|
218
|
-
root: flags.root,
|
|
219
|
-
preprocessor: flags.preprocessor,
|
|
220
|
-
tailwind: flags.tailwind,
|
|
221
|
-
images: flags.images,
|
|
222
|
-
install: flags.install,
|
|
223
|
-
cwd: process.cwd(),
|
|
224
|
-
});
|
|
225
|
-
break;
|
|
226
|
-
|
|
227
|
-
case 'dev':
|
|
228
|
-
banner();
|
|
229
|
-
process.stdout.write(dim(' starting dev server…') + '\n\n');
|
|
230
|
-
await dev({ root: flags.root, port: flags.port, host: flags.host });
|
|
231
|
-
break;
|
|
232
|
-
|
|
233
|
-
case 'build':
|
|
234
|
-
banner();
|
|
235
|
-
process.stdout.write(
|
|
236
|
-
dim(flags.server ? ' building the server…' : ' building for production…') +
|
|
237
|
-
'\n\n',
|
|
238
|
-
);
|
|
239
|
-
await build({ root: flags.root, serverOnly: flags.server });
|
|
240
|
-
process.stdout.write(
|
|
241
|
-
'\n' +
|
|
242
|
-
success(' ✓ ') +
|
|
243
|
-
bold(flags.server ? 'server build complete' : 'build complete') +
|
|
244
|
-
'\n\n',
|
|
245
|
-
);
|
|
246
|
-
break;
|
|
247
|
-
|
|
248
|
-
case 'start': {
|
|
249
|
-
banner();
|
|
250
|
-
process.stdout.write(dim(' self-hosting the built app…') + '\n\n');
|
|
251
|
-
const server = await start({
|
|
252
|
-
root: flags.root,
|
|
253
|
-
port: flags.port,
|
|
254
|
-
host: flags.host,
|
|
255
|
-
threads: flags.threads,
|
|
256
|
-
});
|
|
257
|
-
// A wildcard bind (0.0.0.0/::) is not universally openable, so present a
|
|
258
|
-
// clickable loopback URL and separately flag that it is exposed.
|
|
259
|
-
const wildcard =
|
|
260
|
-
server.host === '0.0.0.0' || server.host === '::' || server.host === '';
|
|
261
|
-
const shownHost = wildcard ? 'localhost' : server.host;
|
|
262
|
-
const exposed =
|
|
263
|
-
server.host !== '127.0.0.1' && server.host !== 'localhost' && server.host !== '::1';
|
|
264
|
-
process.stdout.write(
|
|
265
|
-
accent(' ➜ ') +
|
|
266
|
-
bold(`http://${shownHost}:${String(server.port)}`) +
|
|
267
|
-
dim(` ws channel: ${server.wsPath}`) +
|
|
268
|
-
(exposed
|
|
269
|
-
? '\n' +
|
|
270
|
-
dim(` bound to ${server.host}:${String(server.port)} (exposed beyond loopback)`)
|
|
271
|
-
: '') +
|
|
272
|
-
'\n\n',
|
|
273
|
-
);
|
|
274
|
-
break;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
case 'doctor':
|
|
278
|
-
// Skip the banner for --json so stdout stays valid JSON.
|
|
279
|
-
if (!flags.json) banner();
|
|
280
|
-
await runDoctor({
|
|
281
|
-
root: flags.root,
|
|
282
|
-
cwd: process.cwd(),
|
|
283
|
-
json: flags.json,
|
|
284
|
-
fix: flags.fix,
|
|
285
|
-
});
|
|
286
|
-
break;
|
|
287
|
-
|
|
288
|
-
case 'update':
|
|
289
|
-
banner();
|
|
290
|
-
await runUpdate({
|
|
291
|
-
root: flags.root,
|
|
292
|
-
cwd: process.cwd(),
|
|
293
|
-
yes: flags.yes,
|
|
294
|
-
target: flags.target,
|
|
295
|
-
});
|
|
296
|
-
break;
|
|
297
|
-
|
|
298
|
-
case 'db': {
|
|
299
|
-
// `toiljs db <action> [file]` — no banner so `path`/`export` pipe cleanly.
|
|
300
|
-
const action = rest[0];
|
|
301
|
-
const fileArg = rest[1] !== undefined && !rest[1].startsWith('-') ? rest[1] : undefined;
|
|
302
|
-
runDb(action, fileArg, { root: flags.root });
|
|
303
|
-
break;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
case 'help':
|
|
307
|
-
case '--help':
|
|
308
|
-
case '-h':
|
|
309
|
-
case undefined:
|
|
310
|
-
banner();
|
|
311
|
-
printHelp();
|
|
312
|
-
break;
|
|
313
|
-
|
|
314
|
-
default:
|
|
315
|
-
banner();
|
|
316
|
-
process.stdout.write(dim(` unknown command: ${command}`) + '\n\n');
|
|
317
|
-
printHelp();
|
|
318
|
-
process.exitCode = 1;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
main().catch((err: unknown) => {
|
|
323
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
324
|
-
process.stderr.write('\n' + danger(' ✗ ') + message + '\n');
|
|
325
|
-
process.exitCode = 1;
|
|
326
|
-
});
|
package/src/cli/notify.ts
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Automatic update check, run on every CLI invocation (so `npm run dev` / `npm run build`,
|
|
3
|
-
* which call the toiljs CLI, are covered too). Asks the npm registry for the latest toiljs
|
|
4
|
-
* release (answer cached for an hour in the user's cache dir, network capped at 2 seconds),
|
|
5
|
-
* then warns on stderr when the project's installed toiljs or the running CLI is behind.
|
|
6
|
-
* Never throws and never fails the command. Opt out with TOILJS_NO_UPDATE_CHECK=1 (also
|
|
7
|
-
* honors NO_UPDATE_NOTIFIER and CI).
|
|
8
|
-
*/
|
|
9
|
-
import fs from 'node:fs';
|
|
10
|
-
import os from 'node:os';
|
|
11
|
-
import path from 'node:path';
|
|
12
|
-
import { fileURLToPath } from 'node:url';
|
|
13
|
-
|
|
14
|
-
import { detectPackageManager } from './update.js';
|
|
15
|
-
import { accent, bold, box, dim, version as cliVersion, warn } from './ui.js';
|
|
16
|
-
import { findOutdated, isCacheFresh, type OutdatedRow, parseCheckCache } from './version-check.js';
|
|
17
|
-
|
|
18
|
-
const REGISTRY_URL = 'https://registry.npmjs.org/toiljs/latest';
|
|
19
|
-
const FETCH_TIMEOUT_MS = 2000;
|
|
20
|
-
|
|
21
|
-
/** Where the registry answer is cached: `$XDG_CACHE_HOME`/`~/.cache` + `toiljs/`. */
|
|
22
|
-
function cacheFile(): string {
|
|
23
|
-
const base = process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), '.cache');
|
|
24
|
-
return path.join(base, 'toiljs', 'update-check.json');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Asks the npm registry for the latest published version; null on any failure. */
|
|
28
|
-
async function fetchLatest(): Promise<string | null> {
|
|
29
|
-
const ctrl = new AbortController();
|
|
30
|
-
const timer = setTimeout(() => {
|
|
31
|
-
ctrl.abort();
|
|
32
|
-
}, FETCH_TIMEOUT_MS);
|
|
33
|
-
try {
|
|
34
|
-
const res = await fetch(REGISTRY_URL, {
|
|
35
|
-
signal: ctrl.signal,
|
|
36
|
-
headers: { accept: 'application/json' },
|
|
37
|
-
});
|
|
38
|
-
if (!res.ok) return null;
|
|
39
|
-
const data: unknown = await res.json();
|
|
40
|
-
if (typeof data !== 'object' || data === null) return null;
|
|
41
|
-
const v = (data as Record<string, unknown>).version;
|
|
42
|
-
return typeof v === 'string' ? v : null;
|
|
43
|
-
} catch {
|
|
44
|
-
return null;
|
|
45
|
-
} finally {
|
|
46
|
-
clearTimeout(timer);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* The latest published toiljs version, from the cache when fresh, otherwise from the registry.
|
|
52
|
-
* Failures are cached too (as null) so an offline machine backs off for the TTL instead of
|
|
53
|
-
* paying the fetch timeout on every command.
|
|
54
|
-
*/
|
|
55
|
-
async function resolveLatest(): Promise<string | null> {
|
|
56
|
-
const file = cacheFile();
|
|
57
|
-
try {
|
|
58
|
-
const cached = parseCheckCache(fs.readFileSync(file, 'utf8'));
|
|
59
|
-
if (cached && isCacheFresh(cached, Date.now())) return cached.latest;
|
|
60
|
-
} catch {}
|
|
61
|
-
const latest = await fetchLatest();
|
|
62
|
-
try {
|
|
63
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
64
|
-
fs.writeFileSync(file, JSON.stringify({ latest, checkedAt: Date.now() }));
|
|
65
|
-
} catch {}
|
|
66
|
-
return latest;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** Reads the version of the toiljs resolved in the project's node_modules, if any. */
|
|
70
|
-
function projectToiljsVersion(root: string): string | null {
|
|
71
|
-
try {
|
|
72
|
-
const raw = fs.readFileSync(
|
|
73
|
-
path.join(root, 'node_modules', 'toiljs', 'package.json'),
|
|
74
|
-
'utf8',
|
|
75
|
-
);
|
|
76
|
-
const parsed: unknown = JSON.parse(raw);
|
|
77
|
-
if (typeof parsed !== 'object' || parsed === null) return null;
|
|
78
|
-
const v = (parsed as Record<string, unknown>).version;
|
|
79
|
-
return typeof v === 'string' ? v : null;
|
|
80
|
-
} catch {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function noticeLines(latest: string, rows: OutdatedRow[]): string {
|
|
86
|
-
const header = warn('⚠ ') + bold(`a newer toiljs is available: ${accent(latest)}`);
|
|
87
|
-
const body = rows.map((row) => {
|
|
88
|
-
const where = row.scope === 'project' ? 'this project has' : 'your global CLI is';
|
|
89
|
-
return `${where} ${row.installed}${dim(', update with')} ${accent(row.command)}`;
|
|
90
|
-
});
|
|
91
|
-
return '\n' + box([header, '', ...body], warn) + '\n';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Checks the project install and the running CLI against the latest release and prints a
|
|
96
|
-
* warning to stderr when either is behind. Safe to await unconditionally: bounded by the
|
|
97
|
-
* cache TTL + fetch timeout, and it swallows every error.
|
|
98
|
-
*/
|
|
99
|
-
export async function notifyIfOutdated(rootArg: string | undefined): Promise<void> {
|
|
100
|
-
try {
|
|
101
|
-
const env = process.env;
|
|
102
|
-
if (env.TOILJS_NO_UPDATE_CHECK || env.NO_UPDATE_NOTIFIER || env.CI) return;
|
|
103
|
-
|
|
104
|
-
const latest = await resolveLatest();
|
|
105
|
-
if (!latest) return;
|
|
106
|
-
|
|
107
|
-
const root = path.resolve(rootArg ?? process.cwd());
|
|
108
|
-
const cliDir = path.dirname(fileURLToPath(import.meta.url));
|
|
109
|
-
const cliIsLocal = cliDir.startsWith(path.join(root, 'node_modules') + path.sep);
|
|
110
|
-
const rows = findOutdated(
|
|
111
|
-
latest,
|
|
112
|
-
projectToiljsVersion(root),
|
|
113
|
-
cliVersion(),
|
|
114
|
-
cliIsLocal,
|
|
115
|
-
detectPackageManager(root).name,
|
|
116
|
-
);
|
|
117
|
-
if (rows.length === 0) return;
|
|
118
|
-
process.stderr.write(noticeLines(latest, rows));
|
|
119
|
-
} catch {}
|
|
120
|
-
}
|
package/src/cli/proc.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Spawns `cmd args` in `cwd`, resolving on a 0 exit code and rejecting otherwise. On Windows the
|
|
5
|
-
* `npm`/`pnpm`/`yarn` shims are `.cmd` files that need a shell; passing an args array with
|
|
6
|
-
* `shell: true` is deprecated (DEP0190), so the whole command is passed as one string there
|
|
7
|
-
* (args are fixed/allowlisted, never raw user input). POSIX spawns directly.
|
|
8
|
-
*/
|
|
9
|
-
export function run(
|
|
10
|
-
cmd: string,
|
|
11
|
-
args: string[],
|
|
12
|
-
cwd: string,
|
|
13
|
-
opts: { stdio?: 'ignore' | 'inherit' } = {},
|
|
14
|
-
): Promise<void> {
|
|
15
|
-
return new Promise((resolve, reject) => {
|
|
16
|
-
const onWindows = process.platform === 'win32';
|
|
17
|
-
const stdio = opts.stdio ?? 'ignore';
|
|
18
|
-
const child = onWindows
|
|
19
|
-
? spawn([cmd, ...args].join(' '), { cwd, stdio, shell: true })
|
|
20
|
-
: spawn(cmd, args, { cwd, stdio });
|
|
21
|
-
child.on('error', reject);
|
|
22
|
-
child.on('close', (code) =>
|
|
23
|
-
code === 0 ? resolve() : reject(new Error(`${cmd} exited with code ${String(code)}`)),
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Like {@link run}, but captures stdout/stderr and resolves with them plus the exit code (it never
|
|
30
|
-
* rejects on a non-zero exit, the caller decides). Used to read JSON from tools like
|
|
31
|
-
* `npm-check-updates`. Same Windows shell handling as {@link run}; args are fixed/allowlisted.
|
|
32
|
-
*/
|
|
33
|
-
export function capture(
|
|
34
|
-
cmd: string,
|
|
35
|
-
args: string[],
|
|
36
|
-
cwd: string,
|
|
37
|
-
): Promise<{ stdout: string; stderr: string; code: number }> {
|
|
38
|
-
return new Promise((resolve, reject) => {
|
|
39
|
-
const onWindows = process.platform === 'win32';
|
|
40
|
-
const child = onWindows
|
|
41
|
-
? spawn([cmd, ...args].join(' '), { cwd, shell: true })
|
|
42
|
-
: spawn(cmd, args, { cwd });
|
|
43
|
-
let stdout = '';
|
|
44
|
-
let stderr = '';
|
|
45
|
-
child.stdout?.on('data', (d: Buffer) => {
|
|
46
|
-
stdout += d.toString();
|
|
47
|
-
});
|
|
48
|
-
child.stderr?.on('data', (d: Buffer) => {
|
|
49
|
-
stderr += d.toString();
|
|
50
|
-
});
|
|
51
|
-
child.on('error', reject);
|
|
52
|
-
child.on('close', (code) => {
|
|
53
|
-
resolve({ stdout, stderr, code: code ?? 1 });
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
}
|