typing.works 0.3.0-beta.7 → 0.3.0-beta.9

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/README.md CHANGED
@@ -8,13 +8,13 @@ Typing practice from [typing.works](https://typing.works), in your terminal —
8
8
  macOS · Linux
9
9
 
10
10
  ```sh
11
- curl -fsSL https://raw.githubusercontent.com/pers-dev/typing.works/main/install.sh | sh
11
+ curl -fsSL https://cdn.jsdelivr.net/npm/typing.works/install.sh | sh
12
12
  ```
13
13
 
14
14
  Windows 10 · 11 (PowerShell)
15
15
 
16
16
  ```powershell
17
- irm https://raw.githubusercontent.com/pers-dev/typing.works/main/install.ps1 | iex
17
+ irm https://cdn.jsdelivr.net/npm/typing.works/install.ps1 | iex
18
18
  ```
19
19
 
20
20
  아무것도 미리 깔 필요가 없습니다. 실행 파일을 받아 해시를 대조하고 `~/.local/bin`(Windows 는 `%LOCALAPPDATA%\typingworks\bin`)에 둡니다 — 그다음 `typingworks`.
package/install.ps1 ADDED
@@ -0,0 +1,97 @@
1
+ # typing.works - terminal installer for Windows
2
+ # irm https://cdn.jsdelivr.net/npm/typing.works/install.ps1 | iex
3
+ #
4
+ # What it does
5
+ # 1. Downloads the typing.works npm package (about 2 MB, holds all seven binaries) and takes the one for this PC
6
+ # (Windows 10 1809+ / 11, x64 or arm64)
7
+ # 2. Verifies it against the sha512 the npm registry publishes - stops on mismatch
8
+ # 3. Puts typingworks.exe and typing.works.exe in %LOCALAPPDATA%\typingworks\bin (override: TW_INSTALL_DIR)
9
+ # 4. Adds that folder to your user PATH (skip: TW_NO_MODIFY_PATH=1)
10
+ # The version follows the latest "typing.works" on npm (pin: TW_VERSION). Ctrl+U in the app re-runs this script.
11
+ # No source code is downloaded - only the binary, README and LICENSE.
12
+ # Uninstall: delete that folder and %USERPROFILE%\.typingworks
13
+ # (ASCII only on purpose: Windows PowerShell 5.1 reads BOM-less script files in the ANSI code page.)
14
+ & {
15
+ $ErrorActionPreference = 'Stop'
16
+ $ProgressPreference = 'SilentlyContinue' # the progress bar slows downloads a lot on PowerShell 5.1
17
+ [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
18
+ $reg = if ($env:TW_REGISTRY) { $env:TW_REGISTRY } else { 'https://registry.npmjs.org' } # an npm mirror, if you use one
19
+ $dir = if ($env:TW_INSTALL_DIR) { $env:TW_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA 'typingworks\bin' }
20
+
21
+ # The real CPU - pick arm64 even when x64 PowerShell runs under emulation on ARM
22
+ $arch = $null
23
+ try { $arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString() } catch { }
24
+ if (-not $arch) { $arch = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE } }
25
+ switch -regex ($arch) {
26
+ '^(Arm64|ARM64)$' { $arch = 'arm64' }
27
+ '^(X64|AMD64)$' { $arch = 'x64' }
28
+ default { throw "typing.works: $arch is not supported yet (Windows x64 / arm64)" }
29
+ }
30
+
31
+ # Version and the package's sha512 in one request - latest unless TW_VERSION is set
32
+ $tag = if ($env:TW_VERSION) { $env:TW_VERSION } else { 'latest' }
33
+ $meta = $null
34
+ try { $meta = Invoke-RestMethod -UseBasicParsing "$reg/typing.works/$tag" } catch { }
35
+ if (-not $meta -or -not $meta.version -or -not $meta.dist.integrity) { throw 'typing.works: could not read the npm registry (check your internet connection)' }
36
+ $ver = $meta.version
37
+ $integrity = $meta.dist.integrity
38
+ if ($integrity -notlike 'sha512-*') { throw "typing.works: unexpected integrity format: $integrity" }
39
+ $tar = (Get-Command tar.exe -ErrorAction SilentlyContinue).Source # built in since Windows 10 1803
40
+ if (-not $tar) { throw 'typing.works: tar.exe was not found (Windows 10 1803 or later is needed)' }
41
+ # Download with the built-in curl.exe (Windows 10 1803+). PowerShell 5.1's Invoke-WebRequest follows GitHub's redirect to a
42
+ # signed asset URL but mangles the signature and gets 404 (seen 2026-10-13). Fall back to it only when curl.exe is missing.
43
+ $curl = (Get-Command curl.exe -ErrorAction SilentlyContinue).Source
44
+ function Get-File([string]$from, [string]$to) {
45
+ if ($curl -and $from -notlike 'file:*') {
46
+ & $curl -fsSL --retry 2 -o $to $from
47
+ if ($LASTEXITCODE -ne 0) { throw "typing.works: download failed ($LASTEXITCODE): $from" }
48
+ } else {
49
+ Invoke-WebRequest -UseBasicParsing $from -OutFile $to
50
+ }
51
+ }
52
+ $tmp = Join-Path ([IO.Path]::GetTempPath()) ('typingworks-' + [guid]::NewGuid().ToString('N'))
53
+ New-Item -ItemType Directory -Path $tmp | Out-Null
54
+ try {
55
+ Write-Host "typing.works $ver (win32-$arch) downloading..."
56
+ $tgz = Join-Path $tmp "typing.works-$ver.tgz"
57
+ Get-File "$reg/typing.works/-/typing.works-$ver.tgz" $tgz
58
+ $want = -join ([Convert]::FromBase64String($integrity.Substring(7)) | ForEach-Object { $_.ToString('x2') })
59
+ $got = (Get-FileHash -Algorithm SHA512 $tgz).Hash.ToLower()
60
+ if ($got -ne $want) { throw 'typing.works: checksum mismatch - not installed' }
61
+ $inner = "package/vendor/win32-$arch/typingworks.exe"
62
+ & $tar -xzf $tgz -C $tmp $inner
63
+ if ($LASTEXITCODE -ne 0) { throw "typing.works: could not extract $inner" }
64
+
65
+ New-Item -ItemType Directory -Force -Path $dir | Out-Null
66
+ # A running .exe cannot be deleted but can be renamed - move the old one aside, then place the new one (Ctrl+U comes this way)
67
+ foreach ($n in @('typingworks.exe', 'typing.works.exe')) {
68
+ $p = Join-Path $dir $n
69
+ Remove-Item ($p + '.old') -Force -ErrorAction SilentlyContinue
70
+ if (Test-Path $p) { Move-Item $p ($p + '.old') -Force }
71
+ }
72
+ $exe = Join-Path $dir 'typingworks.exe'
73
+ Copy-Item (Join-Path $tmp ("package\vendor\win32-$arch\typingworks.exe")) $exe
74
+ Copy-Item $exe (Join-Path $dir 'typing.works.exe') # same program under both names
75
+ foreach ($n in @('typingworks.exe.old', 'typing.works.exe.old')) { Remove-Item (Join-Path $dir $n) -Force -ErrorAction SilentlyContinue }
76
+
77
+ # Tell the app it was installed by this script, so Ctrl+U re-runs it (UTF-8 without BOM - user folders may be non-ASCII)
78
+ $tw = Join-Path $HOME '.typingworks'
79
+ New-Item -ItemType Directory -Force -Path $tw | Out-Null
80
+ [IO.File]::WriteAllText((Join-Path $tw 'install-script'), $exe + "`n", (New-Object Text.UTF8Encoding $false))
81
+
82
+ Write-Host "OK typing.works $ver -> $exe"
83
+ $userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
84
+ $has = $false
85
+ if ($userPath) { foreach ($e in $userPath.Split(';')) { if ($e.TrimEnd('\') -ieq $dir.TrimEnd('\')) { $has = $true } } }
86
+ if (-not $has -and $env:TW_NO_MODIFY_PATH -ne '1') {
87
+ $new = if ($userPath) { $userPath.TrimEnd(';') + ';' + $dir } else { $dir }
88
+ [Environment]::SetEnvironmentVariable('Path', $new, 'User')
89
+ $env:Path = $env:Path.TrimEnd(';') + ';' + $dir
90
+ Write-Host " added $dir to your PATH - open a new terminal, then run: typingworks"
91
+ } else {
92
+ Write-Host ' run: typingworks'
93
+ }
94
+ } finally {
95
+ Remove-Item $tmp -Recurse -Force -ErrorAction SilentlyContinue
96
+ }
97
+ }
package/install.sh ADDED
@@ -0,0 +1,97 @@
1
+ #!/bin/sh
2
+ # typing.works — terminal 설치 · install
3
+ # curl -fsSL https://cdn.jsdelivr.net/npm/typing.works/install.sh | sh
4
+ #
5
+ # 하는 일 · what it does
6
+ # 1. npm 의 typing.works 꾸러미(실행 파일 일곱 가지가 든 약 2MB)를 받아 이 기기(macOS · Linux, arm64 · x64 · x86)에 맞는 것만 꺼낸다
7
+ # 2. npm 이 알려 주는 sha512 와 대조한다 — 다르면 멈춘다
8
+ # 3. ~/.local/bin 에 typingworks 와 typing.works 를 둔다(TW_INSTALL_DIR 로 바꿀 수 있다)
9
+ # 4. 그 폴더가 PATH 에 없으면 셸 설정 파일에 한 줄 더하고 알린다
10
+ # 판 번호는 npm 의 typing.works 최신 판을 따른다(TW_VERSION=0.3.0 처럼 고를 수 있다). 앱 안 ^U 가 이 스크립트를 다시 돌린다.
11
+ # 소스 코드는 없다 — npm 꾸러미에는 실행 파일 · 설명서 · 라이선스 · 이 스크립트뿐. 지우기: rm ~/.local/bin/typingworks ~/.local/bin/typing.works ; rm -rf ~/.typingworks
12
+ set -eu
13
+
14
+ REG="${TW_REGISTRY:-https://registry.npmjs.org}" # npm 미러를 쓰는 곳이면 바꾼다
15
+ DIR="${TW_INSTALL_DIR:-$HOME/.local/bin}"
16
+ say() { printf '%s\n' "$*"; }
17
+ die() { printf 'typing.works: %s\n' "$*" >&2; exit 1; }
18
+
19
+ command -v curl >/dev/null 2>&1 || die "curl 이 필요합니다 · curl is required"
20
+ command -v tar >/dev/null 2>&1 || die "tar 가 필요합니다 · tar is required"
21
+
22
+ os="$(uname -s)"; arch="$(uname -m)"
23
+ case "$os" in
24
+ Darwin) os=darwin ;;
25
+ Linux) os=linux ;;
26
+ *) die "$os 은 아직 지원하지 않습니다 — macOS · Linux (Windows 는 PowerShell 설치를 쓰세요) · $os is not supported yet" ;;
27
+ esac
28
+ case "$arch" in
29
+ arm64|aarch64) arch=arm64 ;;
30
+ x86_64|amd64) arch=x64 ;;
31
+ i386|i486|i586|i686) arch=ia32 ;;
32
+ *) die "$arch 은 아직 지원하지 않습니다 · $arch is not supported yet" ;;
33
+ esac
34
+ [ "$os" = darwin ] && [ "$arch" = ia32 ] && die "32비트 macOS 는 지원하지 않습니다 · 32-bit macOS is not supported"
35
+ # Rosetta 로 돌린 셸이어도 진짜 칩에 맞춘다
36
+ if [ "$os" = darwin ] && [ "$arch" = x64 ] && [ "$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0)" = 1 ]; then arch=arm64; fi
37
+
38
+ # 판 번호와 꾸러미의 sha512 를 한 번에 — 판을 안 주면 latest
39
+ meta="$(curl -fsSL "$REG/typing.works/${TW_VERSION:-latest}")" || die "판 정보를 못 읽었습니다(인터넷 연결을 확인하세요) · could not reach the npm registry"
40
+ ver="$(printf '%s' "$meta" | grep -o '"version":"[^"]*"' | head -n 1 | cut -d'"' -f4)"
41
+ integ="$(printf '%s' "$meta" | grep -o '"integrity":"sha512-[^"]*"' | head -n 1 | cut -d'"' -f4)"
42
+ [ -n "$ver" ] && [ -n "$integ" ] || die "판 정보가 이상합니다 · unexpected registry response"
43
+
44
+ # base64 → 16진수(base64 -d 는 GNU · 새 macOS, -D 는 옛 macOS, 없으면 openssl)
45
+ b64hex() {
46
+ for d in "base64 -d" "base64 -D" "openssl base64 -d -A"; do
47
+ h="$(printf '%s' "$1" | $d 2>/dev/null | od -An -v -tx1 | tr -d ' \n')"
48
+ [ -n "$h" ] && { printf '%s' "$h"; return 0; }
49
+ done
50
+ return 1
51
+ }
52
+ want="$(b64hex "${integ#sha512-}")" || die "sha512 를 풀 도구가 없습니다 · no base64 tool"
53
+
54
+ tmp="$(mktemp -d 2>/dev/null || mktemp -d -t typingworks)"
55
+ trap 'rm -rf "$tmp"' EXIT INT TERM
56
+ tgz="$tmp/typing.works-$ver.tgz"
57
+
58
+ say "typing.works $ver ($os-$arch) 받는 중 · downloading…"
59
+ curl -fsSL "$REG/typing.works/-/typing.works-$ver.tgz" -o "$tgz" || die "받지 못했습니다 · download failed"
60
+ if command -v sha512sum >/dev/null 2>&1; then got="$(sha512sum "$tgz" | cut -d' ' -f1)"
61
+ elif command -v shasum >/dev/null 2>&1; then got="$(shasum -a 512 "$tgz" | cut -d' ' -f1)"
62
+ elif command -v openssl >/dev/null 2>&1; then got="$(openssl dgst -sha512 -r "$tgz" | cut -d' ' -f1)"
63
+ else die "sha512 도구가 없어 대조할 수 없습니다 · no sha512 tool"; fi
64
+ [ "$got" = "$want" ] || die "해시가 다릅니다 — 설치하지 않았습니다 · checksum mismatch, not installed"
65
+
66
+ tar -xzf "$tgz" -C "$tmp" "package/vendor/$os-$arch/typingworks" || die "풀지 못했습니다 · could not extract"
67
+ mv "$tmp/package/vendor/$os-$arch/typingworks" "$tmp/typingworks"
68
+ mkdir -p "$DIR"
69
+ # 같은 폴더에 새 이름으로 둔 뒤 바꿔 끼운다 — 돌고 있는 typingworks 가 있어도 안전하다(^U 가 이 길로 온다)
70
+ cp "$tmp/typingworks" "$DIR/.typingworks.new"
71
+ chmod 755 "$DIR/.typingworks.new"
72
+ mv -f "$DIR/.typingworks.new" "$DIR/typingworks"
73
+ ln -sf typingworks "$DIR/typing.works"
74
+
75
+ # 앱이 «스크립트로 깔았다»를 알게 — ^U 가 이 스크립트를 다시 돌린다
76
+ mkdir -p "$HOME/.typingworks"
77
+ printf '%s\n' "$DIR/typingworks" > "$HOME/.typingworks/install-script"
78
+
79
+ say "✓ typing.works $ver → $DIR/typingworks"
80
+
81
+ case ":$PATH:" in
82
+ *":$DIR:"*) say " 실행 · run: typingworks" ;;
83
+ *)
84
+ line="export PATH=\"$DIR:\$PATH\""
85
+ case "${SHELL:-}" in
86
+ */zsh) rc="$HOME/.zshrc" ;;
87
+ */bash) if [ "$os" = darwin ]; then rc="$HOME/.bash_profile"; else rc="$HOME/.bashrc"; fi ;;
88
+ *) rc="$HOME/.profile" ;;
89
+ esac
90
+ if [ "${TW_NO_MODIFY_PATH:-}" != 1 ] && ! grep -qsF "$line" "$rc"; then
91
+ printf '\n# typing.works\n%s\n' "$line" >> "$rc"
92
+ say " $DIR 를 PATH 에 더했습니다($rc) · added to PATH"
93
+ fi
94
+ say " 새 터미널을 열거나 · open a new terminal, or: $line"
95
+ say " 실행 · run: typingworks"
96
+ ;;
97
+ esac
package/package.json CHANGED
@@ -1,18 +1,17 @@
1
1
  {
2
2
  "name": "typing.works",
3
- "version": "0.3.0-beta.7",
3
+ "version": "0.3.0-beta.9",
4
4
  "description": "typing.works in your terminal — Korean & English typing practice, records, stats and ranked matches",
5
5
  "bin": {
6
6
  "typing.works": "bin/typing.works.js",
7
7
  "typingworks": "bin/typing.works.js"
8
8
  },
9
- "files": ["bin", "vendor", "README.md", "LICENSE"],
9
+ "files": ["bin", "vendor", "install.sh", "install.ps1", "README.md", "LICENSE"],
10
10
  "os": ["darwin", "linux", "win32"],
11
11
  "cpu": ["arm64", "x64", "ia32"],
12
12
  "engines": { "node": ">=14" },
13
13
  "license": "SEE LICENSE IN LICENSE",
14
14
  "homepage": "https://typing.works",
15
- "repository": { "type": "git", "url": "git+https://github.com/pers-dev/typing.works.git" },
16
15
  "author": "typing.works",
17
16
  "keywords": ["typing", "typing-practice", "typing-test", "korean", "hangul", "terminal", "tui", "cli", "wpm"]
18
17
  }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file