Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@tekir/cli

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tekir/cli - npm Package Compare versions

Comparing version
0.1.0
to
0.1.1
+45
README.md
<p align="center">
<img src="https://tekir.io/logo.svg" width="80" alt="tekir" />
</p>
<h1 align="center">@tekir/cli</h1>
<p align="center">tekir command-line tool: serve, build, and any provider-registered command</p>
<p align="center">
<a href="https://www.npmjs.com/package/@tekir/cli"><img src="https://img.shields.io/npm/v/@tekir/cli.svg" alt="npm version" /></a>
<a href="https://www.npmjs.com/package/@tekir/cli"><img src="https://img.shields.io/npm/dm/@tekir/cli.svg" alt="npm downloads" /></a>
<a href="https://github.com/tekir-io/tekir/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@tekir/cli.svg" alt="license" /></a>
</p>
<p align="center">
<a href="https://tekir.io">Website</a> · <a href="https://docs.tekir.io">Documentation</a> · <a href="https://github.com/tekir-io/tekir">GitHub</a>
</p>
---
## Installation
```bash
# Globally
bun add -g @tekir/cli
# Or as a dev dependency in your project
bun add -d @tekir/cli
```
## Usage
```bash
tekir serve # Start the server (in-process)
tekir serve --dev # Start with watch mode (NODE_ENV=development)
tekir build --outdir ./dist # Plain bundle
tekir build --compile --outfile server # Single self-contained executable
tekir <command> # Any built-in / provider / user command
```
For full usage and configuration, see the [documentation](https://docs.tekir.io/installation).
## License
MIT
+78
-72

@@ -18,2 +18,11 @@ #!/usr/bin/env node

// arg for an entry path.
//
// `--env-file <path>` (multi) is forwarded to the underlying runtime as
// its native `--env-file` flag, not parsed by tekir. The bin filters out
// missing files (with a warning) before forwarding, so monorepo dev
// scripts that chain optional per-package `.env` files work even when
// some of them don't exist yet. For non-watch in-process commands the
// bin re-execs itself once under the runtime to apply the flags; for
// `serve --dev` the existing `--watch` spawn already covers the same
// surface in a single hop.
import { existsSync, readFileSync } from 'node:fs'

@@ -30,6 +39,3 @@ import { spawn, spawnSync } from 'node:child_process'

* `rest` in original order so the in-app dispatcher and Bun.build see
* only their own flags. `--env-file` is the same surface as Bun's and
* Node 20.6+'s runtime flag of the same name; tekir handles it itself
* because the bin imports the entry in-process and the underlying
* runtime never sees the flag otherwise.
* only their own flags.
*/

@@ -85,39 +91,33 @@ function extractTekirFlags(argv) {

/**
* Minimal `.env` loader matching the dotenv conventions Bun and Node use
* for their own `--env-file` flag:
* - blank lines and `#` comments skipped
* - optional `export KEY=value` prefix
* - single- or double-quoted values are unwrapped
* - shell-provided env (anything already set when tekir started) wins;
* later files override earlier ones for the same key
*
* Caller passes `shellKeys` (a Set of keys that existed before any file
* load) so the precedence rule is independent of load order.
* Strip `--env-file` flags from argv when we're about to re-spawn ourselves
* under the runtime: the runtime applies them as native flags before
* loading our bin, so the bin must not see them again or it would loop.
*/
function loadEnvFile(path, shellKeys) {
let content
try {
content = readFileSync(path, 'utf8')
} catch (err) {
console.error(`[tekir] Could not read --env-file '${path}': ${err.message}`)
process.exit(1)
function stripEnvFileFlags(argv) {
const out = []
for (let i = 0; i < argv.length; i++) {
const t = argv[i]
if (t === '--env-file') { i++; continue }
if (t.startsWith('--env-file=')) continue
out.push(t)
}
for (const rawLine of content.split(/\r?\n/)) {
let line = rawLine.trim()
if (!line || line.startsWith('#')) continue
if (line.startsWith('export ')) line = line.slice('export '.length).trimStart()
const eq = line.indexOf('=')
if (eq === -1) continue
const key = line.slice(0, eq).trim()
if (!key) continue
let value = line.slice(eq + 1).trim()
if (value.length >= 2) {
const f = value[0]
const l = value[value.length - 1]
if ((f === '"' && l === '"') || (f === "'" && l === "'")) {
value = value.slice(1, -1)
}
return out
}
/**
* Filter user-supplied env-file paths to those that exist on disk. Both
* Bun and Node 20.6+'s native `--env-file` flag hard-error on a missing
* file, which would break monorepos that chain optional per-package
* `.env` files. Warn for each absent file so typos still surface.
*/
function existingEnvFiles(paths) {
const out = []
for (const f of paths) {
if (existsSync(f)) {
out.push(f)
} else {
console.warn(`[tekir] --env-file '${f}' not found, skipping`)
}
if (!shellKeys.has(key)) process.env[key] = value
}
return out
}

@@ -159,5 +159,5 @@

console.error('Environment files: pass `--env-file <path>` (multi) to load `.env`-style files')
console.error(' before the entry runs. Shell-provided env wins; later files override earlier')
console.error(' ones. `tekir serve --dev` also forwards them to `bun --watch` so edits to a')
console.error(' loaded `.env` take effect on each restart.')
console.error(' via the runtime\'s own `--env-file` flag (Bun, or Node 20.6+). tekir filters')
console.error(' out missing files with a warning before forwarding, so optional per-package')
console.error(' `.env` files in a monorepo do not need to exist for the rest to load.')
console.error('')

@@ -205,14 +205,22 @@ console.error('Build flags: --target, --format esm|cjs|iife, --minify / --no-minify,')

/**
* `Bun.build` is Bun-only. On Node we re-spawn the same bin under `bun`
* with the original argv preserved; if Bun is not on PATH we print an
* actionable error.
* Re-spawn this same bin under `runtime` with native `--env-file` flags
* applied first. The runtime parses the env-files into its own
* `process.env` before our bin's second invocation imports the entry, so
* we never have to ship a hand-rolled dotenv parser. Exits the parent
* with the child's exit code.
*/
function ensureBunOrReexec() {
if (isBun) return
const result = spawnSync('bun', [process.argv[1] ?? '', ...process.argv.slice(2)], {
stdio: 'inherit',
})
function reexecUnder(runtime, envFilesToForward) {
const childArgv = [
...envFilesToForward.map(f => `--env-file=${f}`),
process.argv[1] ?? '',
...stripEnvFileFlags(rawArgv),
]
const result = spawnSync(runtime, childArgv, { stdio: 'inherit' })
if (result.error && /** @type {NodeJS.ErrnoException} */ (result.error).code === 'ENOENT') {
console.error('[tekir] `tekir build` requires Bun (Bun.build is the bundler).')
console.error(' Install Bun: https://bun.sh, or run via `bunx @tekir/cli build`.')
if (runtime === 'bun') {
console.error('[tekir] `bun` is required for this command but is not on PATH.')
console.error(' Install Bun: https://bun.sh.')
} else {
console.error(`[tekir] '${runtime}' is not on PATH.`)
}
process.exit(1)

@@ -226,13 +234,8 @@ }

const command = argv[0]
const presentEnvFiles = existingEnvFiles(envFiles)
// Preload env files into the parent process before any in-process import
// or subprocess spawn. Shell-provided env wins; later files override
// earlier ones for the same key (matches Bun's and Node's `--env-file`
// load order).
if (envFiles.length > 0) {
const shellKeys = new Set(Object.keys(process.env))
for (const f of envFiles) loadEnvFile(f, shellKeys)
}
if (!command) {
// Bare `tekir`: behaves like `tekir serve`. If env-files were passed,
// re-exec under the current runtime so it loads them first.
if (presentEnvFiles.length > 0) reexecUnder(isBun ? 'bun' : 'node', presentEnvFiles)
const entry = await findEntry(entryFlag)

@@ -245,4 +248,10 @@ await runEntry(entry, undefined, [])

if (command === 'build') {
ensureBunOrReexec()
// From here on we are guaranteed to be running under Bun.
// `Bun.build` is Bun-only. Re-exec under bun if we're on Node, OR if
// the user passed `--env-file` flags (so bun loads them as the build
// process boots and any custom plugin code that reads `process.env`
// sees them).
if (!isBun || presentEnvFiles.length > 0) {
reexecUnder('bun', presentEnvFiles)
}
// We are now guaranteed to be running under Bun with env applied.
const entry = await findEntry(entryFlag)

@@ -262,16 +271,9 @@ const flags = argv.slice(1)

// has to spawn a subprocess; in-app `tekir()` still receives `serve` as
// the command and starts the server normally inside it.
// the command and starts the server normally inside it. `--env-file`
// flags are forwarded to the runtime alongside `--watch` so editing a
// loaded `.env` re-applies on the next restart.
if (command === 'serve' && rest.includes('--dev')) {
const watchRest = rest.filter(a => a !== '--dev')
const runner = isBun ? 'bun' : 'node'
const watchFlags = ['--watch']
// Bun's watch mode re-reads `--env-file` on each restart, so editing
// an `.env` mid-watch picks up immediately. Node 20.6+ also supports
// `--env-file`; older Node versions reject it, so we only forward it
// when running under Bun. Either way the parent has already preloaded
// the files into `process.env`, which the spawned child inherits, so
// initial boot env is correct on both runtimes.
if (isBun) {
for (const f of envFiles) watchFlags.push(`--env-file=${f}`)
}
const watchFlags = ['--watch', ...presentEnvFiles.map(f => `--env-file=${f}`)]
const proc = spawn(runner, [...watchFlags, entry, 'serve', ...watchRest], {

@@ -283,3 +285,7 @@ stdio: 'inherit',

} else {
// Any other command imports the entry in-process. If env-files were
// passed, re-exec under the runtime first so its native `--env-file`
// flag applies them before our second invocation runs the entry.
if (presentEnvFiles.length > 0) reexecUnder(isBun ? 'bun' : 'node', presentEnvFiles)
await runEntry(entry, command, rest)
}
{
"name": "@tekir/cli",
"version": "0.1.0",
"version": "0.1.1",
"description": "tekir command-line tool: serve, build, generate-key, and provider-registered commands.",

@@ -5,0 +5,0 @@ "author": "dev@tekir.io",