diff --git a/.github/actions/rust-prelude/action.yml b/.github/actions/rust-prelude/action.yml
new file mode 100644
index 00000000..05108138
--- /dev/null
+++ b/.github/actions/rust-prelude/action.yml
@@ -0,0 +1,18 @@
+name: Rust test prelude
+description: >-
+ Python (interpreter only, for libpython linking) + Rust toolchain and cache.
+ Shared setup for every Rust test job. The caller must check out the repo first
+ — a local action can't be resolved until the workspace exists.
+
+runs:
+ using: composite
+ steps:
+ # Rust tests link the PyO3 extension against libpython; the interpreter is
+ # needed at runtime but the dev deps are not, so skip the uv sync.
+ - name: Set up Python (libpython only)
+ uses: ./.github/actions/setup-python
+ with:
+ sync: "false"
+
+ - name: Set up Rust
+ uses: ./.github/actions/setup-rust
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e0a492ab..ad892e24 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -36,9 +36,11 @@ jobs:
name: Detect changed paths
runs-on: ubuntu-latest
outputs:
- rust: ${{ steps.filter.outputs.rust }}
- python: ${{ steps.filter.outputs.python }}
- node: ${{ steps.filter.outputs.node }}
+ # Run policy folded in: true on push/dispatch (run everything) or when a
+ # suite's paths changed on a PR. Jobs gate on these directly.
+ rust: ${{ steps.decide.outputs.rust }}
+ python: ${{ steps.decide.outputs.python }}
+ node: ${{ steps.decide.outputs.node }}
steps:
- name: Check out repository
uses: actions/checkout@v7
@@ -71,6 +73,27 @@ jobs:
- '.github/actions/**'
- '.github/workflows/ci.yml'
+ - name: Decide which suites run
+ id: decide
+ # FORCE is true on push and workflow_dispatch — run every suite there.
+ # On PRs honor the path filter.
+ env:
+ FORCE: ${{ github.event_name != 'pull_request' }}
+ RUST: ${{ steps.filter.outputs.rust }}
+ PYTHON: ${{ steps.filter.outputs.python }}
+ NODE: ${{ steps.filter.outputs.node }}
+ run: |
+ decide() {
+ if [ "$FORCE" = "true" ] || [ "$2" = "true" ]; then
+ echo "$1=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "$1=false" >> "$GITHUB_OUTPUT"
+ fi
+ }
+ decide rust "$RUST"
+ decide python "$PYTHON"
+ decide node "$NODE"
+
lint:
name: Lint & Static Analysis
runs-on: ubuntu-latest
@@ -129,24 +152,19 @@ jobs:
rust-test:
name: Rust Tests (SQLite)
needs: changes
- if: needs.changes.outputs.rust == 'true' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
steps:
- - name: Check out repository
- uses: actions/checkout@v7
-
- - name: Set up Python (libpython for the linked extension)
- uses: ./.github/actions/setup-python
- with:
- sync: "false"
-
- - name: Set up Rust
- uses: ./.github/actions/setup-rust
+ - uses: actions/checkout@v7
+ - uses: ./.github/actions/rust-prelude
+ # $pythonLocation is exported to the job env by setup-python at runtime.
- name: Run Rust test suite
- # $pythonLocation is exported to the job env by setup-python at runtime.
run: LD_LIBRARY_PATH="$pythonLocation/lib" cargo test --workspace
+ - name: Run mesh crate tests
+ run: LD_LIBRARY_PATH="$pythonLocation/lib" cargo test -p taskito-mesh
+
- name: Check build with native-async features
run: cargo check --workspace --features native-async
@@ -156,7 +174,7 @@ jobs:
rust-test-postgres:
name: Rust Tests (PostgreSQL)
needs: changes
- if: needs.changes.outputs.rust == 'true' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
services:
postgres:
@@ -173,16 +191,8 @@ jobs:
--health-timeout 5s
--health-retries 10
steps:
- - name: Check out repository
- uses: actions/checkout@v7
-
- - name: Set up Python (libpython for the linked extension)
- uses: ./.github/actions/setup-python
- with:
- sync: "false"
-
- - name: Set up Rust
- uses: ./.github/actions/setup-rust
+ - uses: actions/checkout@v7
+ - uses: ./.github/actions/rust-prelude
- name: Run Rust test suite (PostgreSQL backend)
run: LD_LIBRARY_PATH="$pythonLocation/lib" cargo test --workspace --features postgres,workflows
@@ -192,7 +202,7 @@ jobs:
rust-test-redis:
name: Rust Tests (Redis)
needs: changes
- if: needs.changes.outputs.rust == 'true' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.rust == 'true'
runs-on: ubuntu-latest
services:
redis:
@@ -205,46 +215,18 @@ jobs:
--health-timeout 3s
--health-retries 10
steps:
- - name: Check out repository
- uses: actions/checkout@v7
-
- - name: Set up Python (libpython for the linked extension)
- uses: ./.github/actions/setup-python
- with:
- sync: "false"
-
- - name: Set up Rust
- uses: ./.github/actions/setup-rust
+ - uses: actions/checkout@v7
+ - uses: ./.github/actions/rust-prelude
- name: Run Rust test suite (Redis backend)
run: LD_LIBRARY_PATH="$pythonLocation/lib" cargo test --workspace --features redis,workflows
env:
TASKITO_REDIS_TEST_URL: redis://localhost:6379/15
- rust-test-mesh:
- name: Rust Tests (Mesh)
- needs: changes
- if: needs.changes.outputs.rust == 'true' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
- runs-on: ubuntu-latest
- steps:
- - name: Check out repository
- uses: actions/checkout@v7
-
- - name: Set up Python (libpython for the linked extension)
- uses: ./.github/actions/setup-python
- with:
- sync: "false"
-
- - name: Set up Rust
- uses: ./.github/actions/setup-rust
-
- - name: Run mesh crate tests
- run: LD_LIBRARY_PATH="$pythonLocation/lib" cargo test -p taskito-mesh
-
node-test:
name: Node SDK Tests
needs: changes
- if: needs.changes.outputs.node == 'true' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.node == 'true'
runs-on: ubuntu-latest
steps:
- name: Check out repository
@@ -283,7 +265,7 @@ jobs:
test:
name: Python Tests (${{ matrix.os }} / Python ${{ matrix.python-version }})
needs: [lint, changes]
- if: needs.changes.outputs.python == 'true' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.python == 'true'
runs-on: ${{ matrix.os }}
env:
# setup-python on macOS upgrades certifi via pip; pip's HTTP cache
@@ -349,7 +331,7 @@ jobs:
ci-status:
name: CI status
if: always()
- needs: [changes, lint, rust-test, rust-test-postgres, rust-test-redis, rust-test-mesh, node-test, test]
+ needs: [changes, lint, rust-test, rust-test-postgres, rust-test-redis, node-test, test]
runs-on: ubuntu-latest
steps:
- name: Check that no required job failed
diff --git a/.github/workflows/publish-node.yml b/.github/workflows/publish-node.yml
index 2a1ccd1c..7c76f26c 100644
--- a/.github/workflows/publish-node.yml
+++ b/.github/workflows/publish-node.yml
@@ -2,8 +2,10 @@ name: Publish to npm
# Builds the napi addon as prebuilt per-platform `.node` binaries on native
# runners (no cross-compilation — the same approach the Python publish.yml uses
-# for wheels), then publishes the per-platform `taskito-` packages plus
-# the main `taskito` package to npm via OIDC trusted publishing + provenance.
+# for wheels), then publishes the per-platform `@byteveda/taskito-`
+# packages plus the main `@byteveda/taskito` package to npm via OIDC trusted
+# publishing + provenance. The npm scope sidesteps the spam-detection 403 that
+# unscoped per-platform names trip on first publish.
on:
push:
@@ -272,27 +274,35 @@ jobs:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish per-platform packages
+ id: platforms
if: ${{ !inputs.dry-run }}
working-directory: sdks/node
# Skip any package already live at this version so a rerun after a
- # partial publish can finish the rest instead of aborting on the first.
+ # partial publish can finish the rest. A single platform failing (e.g.
+ # npm spam-detection 403) must NOT abort the run before the main package
+ # publishes — the SDK still installs on every platform that did land.
+ # Record failures and surface them at the end of the job instead.
run: |
+ failed=""
for dir in npm/*/; do
pkg=$(node -p "require('./${dir}package.json').name")
if npm view "${pkg}@${VERSION}" version >/dev/null 2>&1; then
echo "::notice::${pkg}@${VERSION} already published — skipping"
+ elif npm publish "$dir" --provenance --access public; then
+ echo "Published ${pkg}@${VERSION}"
else
- echo "Publishing ${pkg}@${VERSION}"
- npm publish "$dir" --provenance --access public
+ echo "::warning::Failed to publish ${pkg}@${VERSION}"
+ failed="${failed} ${pkg}"
fi
done
+ echo "failed=${failed# }" >> "$GITHUB_OUTPUT"
- name: Publish main package
if: ${{ !inputs.dry-run }}
working-directory: sdks/node
run: |
- if npm view "taskito@${VERSION}" version >/dev/null 2>&1; then
- echo "::notice::taskito@${VERSION} already published — skipping"
+ if npm view "@byteveda/taskito@${VERSION}" version >/dev/null 2>&1; then
+ echo "::notice::@byteveda/taskito@${VERSION} already published — skipping"
else
npm publish --provenance --access public
fi
@@ -306,13 +316,13 @@ jobs:
if: ${{ !inputs.dry-run }}
run: |
for _attempt in 1 2 3 4 5; do
- if npm view "taskito@${VERSION}" version >/dev/null 2>&1; then
- echo "taskito@${VERSION} live on npm"
+ if npm view "@byteveda/taskito@${VERSION}" version >/dev/null 2>&1; then
+ echo "@byteveda/taskito@${VERSION} live on npm"
exit 0
fi
sleep 15
done
- echo "::error::taskito@${VERSION} not found on npm"
+ echo "::error::@byteveda/taskito@${VERSION} not found on npm"
exit 1
- name: Create git tag
@@ -336,3 +346,17 @@ jobs:
--title "taskito (Node) v${VERSION}" \
--generate-notes
fi
+
+ # The main package + tag + release are done; only now flag any platform
+ # binary that didn't publish, so a missing target turns the job red for a
+ # maintainer to chase without having blocked the otherwise-usable release.
+ - name: Fail if any platform package was skipped
+ if: ${{ always() && !inputs.dry-run && steps.platforms.outputs.failed != '' }}
+ # Pass the list via env, not inline ${{ }} expansion, so a package name
+ # can't break out of the shell script (template-injection defense).
+ env:
+ FAILED_PLATFORMS: ${{ steps.platforms.outputs.failed }}
+ run: |
+ echo "::error::Platform packages that did not publish: ${FAILED_PLATFORMS}"
+ echo "::error::Install on those platforms will fail until they are republished."
+ exit 1
diff --git a/docs/app/components/landing/sections.tsx b/docs/app/components/landing/sections.tsx
index 51114862..404859f2 100644
--- a/docs/app/components/landing/sections.tsx
+++ b/docs/app/components/landing/sections.tsx
@@ -411,7 +411,7 @@ export function CTA() {
-
+
diff --git a/docs/content/docs/node/api-reference/context.mdx b/docs/content/docs/node/api-reference/context.mdx
index d9a8b870..abe5bba6 100644
--- a/docs/content/docs/node/api-reference/context.mdx
+++ b/docs/content/docs/node/api-reference/context.mdx
@@ -4,7 +4,7 @@ description: "currentJob() — the running task's job context."
---
```ts
-import { currentJob } from "taskito";
+import { currentJob } from "@byteveda/taskito";
const job = currentJob(); // JobContext | undefined
```
@@ -36,7 +36,7 @@ cancellation flow.
## `useResource`
```ts
-import { useResource } from "taskito";
+import { useResource } from "@byteveda/taskito";
const db = await useResource
("db"); // inside a running task
```
diff --git a/docs/content/docs/node/api-reference/errors.mdx b/docs/content/docs/node/api-reference/errors.mdx
index e447af6c..ef4c1e77 100644
--- a/docs/content/docs/node/api-reference/errors.mdx
+++ b/docs/content/docs/node/api-reference/errors.mdx
@@ -7,7 +7,7 @@ Every error the SDK throws extends `TaskitoError`, so a single `catch` can scope
all of them; the specific subclasses let you branch on what went wrong.
```ts
-import { TaskitoError, ResourceNotFoundError } from "taskito";
+import { TaskitoError, ResourceNotFoundError } from "@byteveda/taskito";
try {
await runJob();
diff --git a/docs/content/docs/node/api-reference/queue.mdx b/docs/content/docs/node/api-reference/queue.mdx
index 9bb7c1ff..df34c064 100644
--- a/docs/content/docs/node/api-reference/queue.mdx
+++ b/docs/content/docs/node/api-reference/queue.mdx
@@ -4,7 +4,7 @@ description: "Construct a queue and the full producer/admin API."
---
```ts
-import { Queue } from "taskito";
+import { Queue } from "@byteveda/taskito";
const queue = new Queue(options);
```
diff --git a/docs/content/docs/node/api-reference/serializers.mdx b/docs/content/docs/node/api-reference/serializers.mdx
index f347f10b..b0951ab9 100644
--- a/docs/content/docs/node/api-reference/serializers.mdx
+++ b/docs/content/docs/node/api-reference/serializers.mdx
@@ -4,8 +4,8 @@ description: "JsonSerializer, MsgpackSerializer, and the Serializer interface."
---
```ts
-import { Queue, JsonSerializer, MsgpackSerializer } from "taskito";
-import type { Serializer } from "taskito";
+import { Queue, JsonSerializer, MsgpackSerializer } from "@byteveda/taskito";
+import type { Serializer } from "@byteveda/taskito";
```
## Built-ins
diff --git a/docs/content/docs/node/getting-started/installation.mdx b/docs/content/docs/node/getting-started/installation.mdx
index 8c304f08..45654cfa 100644
--- a/docs/content/docs/node/getting-started/installation.mdx
+++ b/docs/content/docs/node/getting-started/installation.mdx
@@ -7,7 +7,7 @@ The Node.js SDK is a thin [napi-rs](https://napi.rs) shell over the Taskito Rust
core — peer to the Python SDK, with **no Python dependency**.
```bash
-pnpm add taskito
+pnpm add @byteveda/taskito
```
Requires Node.js >= 18. Ships as dual **ESM + CommonJS** with bundled type
@@ -35,7 +35,7 @@ the `postgres,redis,workflows,mesh` cargo features enabled.
## Pick a backend
```ts
-import { Queue } from "taskito";
+import { Queue } from "@byteveda/taskito";
new Queue({ dbPath: "taskito.db" }); // SQLite (default)
new Queue({ backend: "postgres", dsn: process.env.PG_URL, schema: "taskito" });
diff --git a/docs/content/docs/node/getting-started/quickstart.mdx b/docs/content/docs/node/getting-started/quickstart.mdx
index 39c6d0b2..13eb03ff 100644
--- a/docs/content/docs/node/getting-started/quickstart.mdx
+++ b/docs/content/docs/node/getting-started/quickstart.mdx
@@ -6,7 +6,7 @@ description: "Define a task, enqueue a job, run a worker, await the result — i
Four steps: construct a queue, register a task, enqueue a job, run a worker.
```ts
-import { Queue } from "taskito";
+import { Queue } from "@byteveda/taskito";
const queue = new Queue({ dbPath: "taskito.db" });
diff --git a/docs/content/docs/node/guides/core/cancellation.mdx b/docs/content/docs/node/guides/core/cancellation.mdx
index e432a76f..787ec5c5 100644
--- a/docs/content/docs/node/guides/core/cancellation.mdx
+++ b/docs/content/docs/node/guides/core/cancellation.mdx
@@ -7,7 +7,7 @@ Cancellation is **cooperative**. A running task reads its context via
`currentJob()` and watches the `AbortSignal`:
```ts
-import { currentJob } from "taskito";
+import { currentJob } from "@byteveda/taskito";
queue.task("download", async (url: string) => {
const { signal } = currentJob() ?? {};
diff --git a/docs/content/docs/node/guides/core/predicates.mdx b/docs/content/docs/node/guides/core/predicates.mdx
index 77a7cbef..efe53be4 100644
--- a/docs/content/docs/node/guides/core/predicates.mdx
+++ b/docs/content/docs/node/guides/core/predicates.mdx
@@ -34,7 +34,7 @@ queue.gate("charge", ({ args }) => args[0] <= 10_000);
Combine predicates with `allOf`, `anyOf`, and `not`:
```ts
-import { allOf, anyOf, not } from "taskito";
+import { allOf, anyOf, not } from "@byteveda/taskito";
const businessHours = () => {
const h = new Date().getHours();
diff --git a/docs/content/docs/node/guides/core/streaming.mdx b/docs/content/docs/node/guides/core/streaming.mdx
index 7f7b42ac..b5725019 100644
--- a/docs/content/docs/node/guides/core/streaming.mdx
+++ b/docs/content/docs/node/guides/core/streaming.mdx
@@ -13,7 +13,7 @@ Call `currentJob().publish(value)` from inside the task. The value must be
JSON-serializable.
```ts
-import { currentJob } from "taskito";
+import { currentJob } from "@byteveda/taskito";
queue.task("train", async (epochs: number) => {
const job = currentJob();
diff --git a/docs/content/docs/node/guides/extensibility/serializers.mdx b/docs/content/docs/node/guides/extensibility/serializers.mdx
index eba847c7..d2c29cb8 100644
--- a/docs/content/docs/node/guides/extensibility/serializers.mdx
+++ b/docs/content/docs/node/guides/extensibility/serializers.mdx
@@ -15,7 +15,7 @@ concern.
for confidentiality **and** integrity.
```ts
-import { Queue, MsgpackSerializer } from "taskito";
+import { Queue, MsgpackSerializer } from "@byteveda/taskito";
new Queue({ dbPath: "taskito.db", serializer: new MsgpackSerializer() });
```
@@ -25,7 +25,7 @@ new Queue({ dbPath: "taskito.db", serializer: new MsgpackSerializer() });
Implement the `Serializer` interface — `serialize` to bytes, `deserialize` back:
```ts
-import type { Serializer } from "taskito";
+import type { Serializer } from "@byteveda/taskito";
const mySerializer: Serializer = {
serialize: (value) => Buffer.from(JSON.stringify(value)),
diff --git a/docs/content/docs/node/guides/integrations/express.mdx b/docs/content/docs/node/guides/integrations/express.mdx
index 9fe71e13..94644969 100644
--- a/docs/content/docs/node/guides/integrations/express.mdx
+++ b/docs/content/docs/node/guides/integrations/express.mdx
@@ -7,7 +7,7 @@ Peer dependency: `express`. Import from the `taskito/contrib/express` subpath.
```ts
import express from "express";
-import { taskitoRouter, taskitoDashboard } from "taskito/contrib/express";
+import { taskitoRouter, taskitoDashboard } from "@byteveda/taskito/contrib/express";
const app = express();
diff --git a/docs/content/docs/node/guides/integrations/fastify.mdx b/docs/content/docs/node/guides/integrations/fastify.mdx
index c2140a8d..c191ebe5 100644
--- a/docs/content/docs/node/guides/integrations/fastify.mdx
+++ b/docs/content/docs/node/guides/integrations/fastify.mdx
@@ -10,7 +10,7 @@ import Fastify from "fastify";
import {
taskitoFastify,
taskitoDashboardPlugin,
-} from "taskito/contrib/fastify";
+} from "@byteveda/taskito/contrib/fastify";
const app = Fastify();
diff --git a/docs/content/docs/node/guides/integrations/nest.mdx b/docs/content/docs/node/guides/integrations/nest.mdx
index 03d8d3a5..61acea83 100644
--- a/docs/content/docs/node/guides/integrations/nest.mdx
+++ b/docs/content/docs/node/guides/integrations/nest.mdx
@@ -8,7 +8,7 @@ Peer dependencies: `@nestjs/common` + `reflect-metadata`. Import from the
```ts
import { Module } from "@nestjs/common";
-import { TaskitoModule } from "taskito/contrib/nest";
+import { TaskitoModule } from "@byteveda/taskito/contrib/nest";
@Module({
imports: [TaskitoModule.forRoot(queue)],
@@ -23,7 +23,7 @@ export class AppModule {}
```ts
import { Injectable } from "@nestjs/common";
-import { TaskitoService } from "taskito/contrib/nest";
+import { TaskitoService } from "@byteveda/taskito/contrib/nest";
@Injectable()
export class ReportService {
diff --git a/docs/content/docs/node/guides/integrations/otel.mdx b/docs/content/docs/node/guides/integrations/otel.mdx
index 506f5d38..6715cd09 100644
--- a/docs/content/docs/node/guides/integrations/otel.mdx
+++ b/docs/content/docs/node/guides/integrations/otel.mdx
@@ -7,7 +7,7 @@ Peer dependency: `@opentelemetry/api`. Import from the `taskito/contrib/otel`
subpath — it is not exported from the main barrel.
```ts
-import { otelMiddleware } from "taskito/contrib/otel";
+import { otelMiddleware } from "@byteveda/taskito/contrib/otel";
queue.use(otelMiddleware());
```
diff --git a/docs/content/docs/node/guides/integrations/prometheus.mdx b/docs/content/docs/node/guides/integrations/prometheus.mdx
index cf321c3b..ce4932c2 100644
--- a/docs/content/docs/node/guides/integrations/prometheus.mdx
+++ b/docs/content/docs/node/guides/integrations/prometheus.mdx
@@ -10,7 +10,7 @@ subpath.
import {
prometheusMiddleware,
PrometheusStatsCollector,
-} from "taskito/contrib/prometheus";
+} from "@byteveda/taskito/contrib/prometheus";
import { register } from "prom-client";
import express from "express";
diff --git a/docs/content/docs/node/guides/integrations/sentry.mdx b/docs/content/docs/node/guides/integrations/sentry.mdx
index 4f6eb75e..3db58bad 100644
--- a/docs/content/docs/node/guides/integrations/sentry.mdx
+++ b/docs/content/docs/node/guides/integrations/sentry.mdx
@@ -8,7 +8,7 @@ registering the middleware. Import from the `taskito/contrib/sentry` subpath.
```ts
import * as Sentry from "@sentry/node";
-import { sentryMiddleware } from "taskito/contrib/sentry";
+import { sentryMiddleware } from "@byteveda/taskito/contrib/sentry";
Sentry.init({ dsn: process.env.SENTRY_DSN });
diff --git a/docs/content/docs/node/guides/observability/logging.mdx b/docs/content/docs/node/guides/observability/logging.mdx
index c5f9e760..e420b519 100644
--- a/docs/content/docs/node/guides/observability/logging.mdx
+++ b/docs/content/docs/node/guides/observability/logging.mdx
@@ -8,7 +8,7 @@ default, so it never pollutes stdout (the CLI's `--json` output and piped data
stay clean). Taskito uses it internally; it is exported for your own use too.
```ts
-import { createLogger } from "taskito";
+import { createLogger } from "@byteveda/taskito";
const log = createLogger("billing"); // tagged [taskito:billing]
@@ -24,7 +24,7 @@ queue.task("charge", async (amount: number) => {
read once from `TASKITO_LOG_LEVEL`; override it at runtime:
```ts
-import { setLogLevel } from "taskito";
+import { setLogLevel } from "@byteveda/taskito";
setLogLevel("debug"); // global, immediate
```
@@ -58,7 +58,7 @@ Replace the output sink to route logs to a file, JSON transport, or a test
buffer — globally and immediately:
```ts
-import { setLogSink } from "taskito";
+import { setLogSink } from "@byteveda/taskito";
setLogSink((level, line) => myTransport.write({ level, line }));
```
diff --git a/docs/content/docs/node/guides/observability/monitoring.mdx b/docs/content/docs/node/guides/observability/monitoring.mdx
index c36ed74b..560c30d1 100644
--- a/docs/content/docs/node/guides/observability/monitoring.mdx
+++ b/docs/content/docs/node/guides/observability/monitoring.mdx
@@ -34,7 +34,7 @@ A running task reports progress through its job context; inspection and the
dashboard surface it live:
```ts
-import { currentJob } from "taskito";
+import { currentJob } from "@byteveda/taskito";
queue.task("import", async (rows: Row[]) => {
const job = currentJob();
diff --git a/docs/content/docs/node/guides/operations/dashboard.mdx b/docs/content/docs/node/guides/operations/dashboard.mdx
index 4ad5f154..3ef31f2f 100644
--- a/docs/content/docs/node/guides/operations/dashboard.mdx
+++ b/docs/content/docs/node/guides/operations/dashboard.mdx
@@ -14,7 +14,7 @@ taskito --db taskito.db dashboard --port 8787
Or programmatically:
```ts
-import { Queue, serveDashboard } from "taskito";
+import { Queue, serveDashboard } from "@byteveda/taskito";
const queue = new Queue({ dbPath: "taskito.db" });
const server = serveDashboard(queue, { port: 8787 });
diff --git a/docs/content/docs/node/guides/operations/keda.mdx b/docs/content/docs/node/guides/operations/keda.mdx
index fdaf2a9f..5bed8a32 100644
--- a/docs/content/docs/node/guides/operations/keda.mdx
+++ b/docs/content/docs/node/guides/operations/keda.mdx
@@ -9,7 +9,7 @@ depth. The SDK ships a scaler server that KEDA's `metrics-api` scaler polls.
## Scaler server
```ts
-import { Queue, serveScaler } from "taskito";
+import { Queue, serveScaler } from "@byteveda/taskito";
const queue = new Queue({ backend: "postgres", dsn: process.env.DATABASE_URL });
serveScaler(queue, { port: 9091, targetQueueDepth: 10 });
diff --git a/docs/content/docs/node/guides/operations/testing.mdx b/docs/content/docs/node/guides/operations/testing.mdx
index 29240b8c..f2f77b1b 100644
--- a/docs/content/docs/node/guides/operations/testing.mdx
+++ b/docs/content/docs/node/guides/operations/testing.mdx
@@ -12,7 +12,7 @@ import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, expect, it } from "vitest";
-import { Queue, type Worker } from "taskito";
+import { Queue, type Worker } from "@byteveda/taskito";
let worker: Worker | undefined;
afterEach(() => {
@@ -59,7 +59,7 @@ the test — the worker injects whatever is registered, so no real connection is
opened:
```ts
-import { useResource } from "taskito";
+import { useResource } from "@byteveda/taskito";
queue.resource("db", () => fakeDb);
queue.task("sync", async () => {
diff --git a/docs/content/docs/node/guides/operations/troubleshooting.mdx b/docs/content/docs/node/guides/operations/troubleshooting.mdx
index de5bd9bf..bef9af10 100644
--- a/docs/content/docs/node/guides/operations/troubleshooting.mdx
+++ b/docs/content/docs/node/guides/operations/troubleshooting.mdx
@@ -7,7 +7,7 @@ Turn on debug logs first — they show the worker claiming, running, and settlin
jobs:
```ts
-import { setLogLevel } from "taskito";
+import { setLogLevel } from "@byteveda/taskito";
setLogLevel("debug");
// or: TASKITO_LOG_LEVEL=debug node app.js
```
diff --git a/docs/content/docs/node/guides/reliability/guarantees.mdx b/docs/content/docs/node/guides/reliability/guarantees.mdx
index af3eec43..f5e5771a 100644
--- a/docs/content/docs/node/guides/reliability/guarantees.mdx
+++ b/docs/content/docs/node/guides/reliability/guarantees.mdx
@@ -25,7 +25,7 @@ Because a job may run more than once, make side effects idempotent:
[`uniqueKey`](/node/guides/reliability/idempotency).
```ts
-import { currentJob } from "taskito";
+import { currentJob } from "@byteveda/taskito";
queue.task("charge", async (orderId: string) => {
const job = currentJob();
diff --git a/docs/content/docs/node/guides/resources/dependency-injection.mdx b/docs/content/docs/node/guides/resources/dependency-injection.mdx
index 2e88cba4..cc845d7d 100644
--- a/docs/content/docs/node/guides/resources/dependency-injection.mdx
+++ b/docs/content/docs/node/guides/resources/dependency-injection.mdx
@@ -8,7 +8,7 @@ constructing those inside every handler, register them once as **resources** and
let the worker build, share, and tear them down with the right lifetime.
```ts
-import { Queue, useResource } from "taskito";
+import { Queue, useResource } from "@byteveda/taskito";
import { Pool } from "pg";
const queue = new Queue({ dbPath: "tasks.db" });
@@ -142,7 +142,7 @@ Register a stub factory to swap a real dependency in tests. `mockResource(value)
wraps a value as a factory and records how often it was built:
```ts
-import { mockResource } from "taskito";
+import { mockResource } from "@byteveda/taskito";
const db = mockResource({ query: async () => fakeRows });
queue.resource("db", db.factory);
diff --git a/docs/content/docs/node/guides/resources/index.mdx b/docs/content/docs/node/guides/resources/index.mdx
index e20e17d9..89cb202f 100644
--- a/docs/content/docs/node/guides/resources/index.mdx
+++ b/docs/content/docs/node/guides/resources/index.mdx
@@ -8,7 +8,7 @@ real dependencies (database pools, HTTP clients, cloud SDKs) are not. The Node
SDK keeps those on the worker and passes only plain data through the queue.
```ts
-import { Queue, useResource } from "taskito";
+import { Queue, useResource } from "@byteveda/taskito";
import { Pool } from "pg";
const queue = new Queue({ dbPath: "tasks.db" });
diff --git a/docs/content/docs/node/more/examples/benchmark.mdx b/docs/content/docs/node/more/examples/benchmark.mdx
index 31347690..891d95f6 100644
--- a/docs/content/docs/node/more/examples/benchmark.mdx
+++ b/docs/content/docs/node/more/examples/benchmark.mdx
@@ -10,7 +10,7 @@ jobs, drains them with a worker, and reports the three rates that bound a queue.
## benchmark.ts
```ts
-import { Queue } from "taskito";
+import { Queue } from "@byteveda/taskito";
const N = 50_000;
const queue = new Queue({ dbPath: "bench.db" });
diff --git a/docs/content/docs/node/more/examples/bulk-emails.mdx b/docs/content/docs/node/more/examples/bulk-emails.mdx
index 7c3434f9..46bf0e4c 100644
--- a/docs/content/docs/node/more/examples/bulk-emails.mdx
+++ b/docs/content/docs/node/more/examples/bulk-emails.mdx
@@ -20,7 +20,7 @@ One job per recipient keeps retries and failures isolated — a bad address neve
blocks the rest. The limits cap how fast and how many run at once.
```ts
-import { Queue } from "taskito";
+import { Queue } from "@byteveda/taskito";
export const queue = new Queue({ dbPath: "bulk-email.db" });
diff --git a/docs/content/docs/node/more/examples/data-pipeline.mdx b/docs/content/docs/node/more/examples/data-pipeline.mdx
index b5fbd87e..c56f1b22 100644
--- a/docs/content/docs/node/more/examples/data-pipeline.mdx
+++ b/docs/content/docs/node/more/examples/data-pipeline.mdx
@@ -33,7 +33,7 @@ passing results down the graph — the standard ETL shape. `load` runs only afte
both transforms complete. The long transform reports progress as it goes.
```ts
-import { Queue, currentJob } from "taskito";
+import { Queue, currentJob } from "@byteveda/taskito";
export const queue = new Queue({ dbPath: "pipeline.db" });
diff --git a/docs/content/docs/node/more/examples/express-service.mdx b/docs/content/docs/node/more/examples/express-service.mdx
index 9f2bd5ee..ab51a681 100644
--- a/docs/content/docs/node/more/examples/express-service.mdx
+++ b/docs/content/docs/node/more/examples/express-service.mdx
@@ -25,7 +25,7 @@ cancel request stops it cleanly.
```ts
import express from "express";
-import { Queue, currentJob } from "taskito";
+import { Queue, currentJob } from "@byteveda/taskito";
const queue = new Queue({ dbPath: "image-service.db" });
@@ -107,7 +107,7 @@ The worker is a separate process that shares the same database. It registers the
same task so it knows how to run `processImage`.
```ts
-import { Queue, currentJob } from "taskito";
+import { Queue, currentJob } from "@byteveda/taskito";
const queue = new Queue({ dbPath: "image-service.db" });
diff --git a/docs/content/docs/node/more/examples/index.mdx b/docs/content/docs/node/more/examples/index.mdx
index fbe10cb9..c04ffc9f 100644
--- a/docs/content/docs/node/more/examples/index.mdx
+++ b/docs/content/docs/node/more/examples/index.mdx
@@ -18,5 +18,5 @@ on the [core guides](/node/guides/core/tasks) — read those for the concepts, c
| [Predicate-gated jobs](/node/more/examples/predicate-gated-jobs) | Enqueue-time gates with `allOf` / `anyOf` / `not` predicate composition |
| [Benchmark](/node/more/examples/benchmark) | Measuring enqueue, processing, and end-to-end latency and throughput |
-Every snippet targets the standalone Node SDK — `import { Queue } from "taskito"` —
+Every snippet targets the standalone Node SDK — `import { Queue } from "@byteveda/taskito"` —
with no Python in the loop. Pick the one closest to your problem and start there.
diff --git a/docs/content/docs/node/more/examples/notifications.mdx b/docs/content/docs/node/more/examples/notifications.mdx
index 91b05dbd..27a97107 100644
--- a/docs/content/docs/node/more/examples/notifications.mdx
+++ b/docs/content/docs/node/more/examples/notifications.mdx
@@ -21,7 +21,7 @@ notifications/
Each channel is its own task so they retry, rate-limit, and scale independently.
```ts
-import { Queue } from "taskito";
+import { Queue } from "@byteveda/taskito";
export const queue = new Queue({ dbPath: "notifications.db" });
diff --git a/docs/content/docs/node/more/examples/predicate-gated-jobs.mdx b/docs/content/docs/node/more/examples/predicate-gated-jobs.mdx
index 869f1b3c..082cffbb 100644
--- a/docs/content/docs/node/more/examples/predicate-gated-jobs.mdx
+++ b/docs/content/docs/node/more/examples/predicate-gated-jobs.mdx
@@ -19,7 +19,7 @@ A predicate receives `{ taskName, args }` — the positional args after any
`onEnqueue` rewrites. Compose them with `allOf` / `anyOf` / `not`.
```ts
-import type { Predicate } from "taskito";
+import type { Predicate } from "@byteveda/taskito";
export const duringBusinessHours: Predicate = () => {
const hour = new Date().getUTCHours();
@@ -39,7 +39,7 @@ export const underQuota: Predicate = ({ args }) => {
`queue.gate` attaches one or more predicates to a task; every gate must pass.
```ts
-import { Queue, allOf, not } from "taskito";
+import { Queue, allOf, not } from "@byteveda/taskito";
import { duringBusinessHours, featureEnabled, underQuota } from "./predicates";
export const queue = new Queue({ dbPath: "gated.db" });
@@ -58,7 +58,7 @@ queue.gate("exportData", allOf(underQuota, not(duringBusinessHours))); // off-pe
A rejected enqueue throws synchronously — handle it where you submit.
```ts
-import { PredicateRejectedError } from "taskito";
+import { PredicateRejectedError } from "@byteveda/taskito";
try {
queue.enqueue("sendPromo", ["newsletter-subscribers"]);
diff --git a/docs/content/docs/node/more/examples/saga-checkout.mdx b/docs/content/docs/node/more/examples/saga-checkout.mdx
index dcfa7088..d4fbf93b 100644
--- a/docs/content/docs/node/more/examples/saga-checkout.mdx
+++ b/docs/content/docs/node/more/examples/saga-checkout.mdx
@@ -14,7 +14,7 @@ Declare each forward task and its rollback. A compensator receives the forward
step's result as its single argument, so it knows exactly what to undo.
```ts
-import { Queue } from "taskito";
+import { Queue } from "@byteveda/taskito";
export const queue = new Queue({ dbPath: "checkout.db" });
diff --git a/docs/content/docs/node/more/examples/web-scraper.mdx b/docs/content/docs/node/more/examples/web-scraper.mdx
index f6922356..6afef97b 100644
--- a/docs/content/docs/node/more/examples/web-scraper.mdx
+++ b/docs/content/docs/node/more/examples/web-scraper.mdx
@@ -24,7 +24,7 @@ backoff. Network tasks run on a dedicated `network` queue so a backlog there
never starves CPU-bound extraction.
```ts
-import { Queue } from "taskito";
+import { Queue } from "@byteveda/taskito";
export const queue = new Queue({ dbPath: "scraper.db" });
diff --git a/sdks/node/README.md b/sdks/node/README.md
index 195ee04a..c12f3379 100644
--- a/sdks/node/README.md
+++ b/sdks/node/README.md
@@ -8,19 +8,19 @@ share storage (SQLite, PostgreSQL, or Redis).
## Install
```bash
-pnpm add taskito
+pnpm add @byteveda/taskito
```
Requires Node.js >= 18. Ships as dual ESM + CommonJS. A prebuilt native binary is
installed automatically for your platform via an optional per-platform package
-(`taskito--`) — linux x64/arm64 (gnu + musl), macOS x64/arm64, and
+(`@byteveda/taskito--`) — linux x64/arm64 (gnu + musl), macOS x64/arm64, and
Windows x64. On a platform without a prebuilt, build from source with the Rust
toolchain + napi-rs CLI (`pnpm build:native`).
## Quickstart
```ts
-import { Queue } from "taskito";
+import { Queue } from "@byteveda/taskito";
const queue = new Queue({ dbPath: "taskito.db" });
@@ -63,7 +63,7 @@ pending/running), `metadata`, `namespace`.
Cancellation is cooperative. A running task reads its context via `currentJob()`:
```ts
-import { currentJob } from "taskito";
+import { currentJob } from "@byteveda/taskito";
queue.task("download", async (url: string) => {
const { signal } = currentJob() ?? {};
@@ -105,7 +105,7 @@ Args and results are serialized with a pluggable `Serializer` (default
payloads as opaque bytes.
```ts
-import { Queue, MsgpackSerializer } from "taskito";
+import { Queue, MsgpackSerializer } from "@byteveda/taskito";
new Queue({ dbPath: "taskito.db", serializer: new MsgpackSerializer() });
```
@@ -358,7 +358,7 @@ taskito --db taskito.db dashboard --port 8787
Or programmatically:
```ts
-import { Queue, serveDashboard } from "taskito";
+import { Queue, serveDashboard } from "@byteveda/taskito";
const queue = new Queue({ dbPath: "taskito.db" });
const server = serveDashboard(queue, { port: 8787 });
@@ -402,8 +402,8 @@ package or exported from the `taskito` barrel.
### Observability
```ts
-import { otelMiddleware } from "taskito/contrib/otel"; // peer: @opentelemetry/api
-import { prometheusMiddleware, PrometheusStatsCollector } from "taskito/contrib/prometheus"; // peer: prom-client
+import { otelMiddleware } from "@byteveda/taskito/contrib/otel"; // peer: @opentelemetry/api
+import { prometheusMiddleware, PrometheusStatsCollector } from "@byteveda/taskito/contrib/prometheus"; // peer: prom-client
queue.use(otelMiddleware()); // one span per execution: taskito.execute.
queue.use(prometheusMiddleware()); // taskito_jobs_total, _job_duration_seconds, _active_workers, _retries_total
@@ -418,7 +418,7 @@ OTel options: `tracerName`, `attributePrefix`, `spanName(ctx)`, `extraAttributes
(metrics for one namespace are built once per registry, so multiple middlewares are safe).
```ts
-import { sentryMiddleware } from "taskito/contrib/sentry"; // peer: @sentry/node
+import { sentryMiddleware } from "@byteveda/taskito/contrib/sentry"; // peer: @sentry/node
queue.use(sentryMiddleware()); // call Sentry.init(...) yourself first
```
@@ -433,11 +433,11 @@ to also report each intermediate failure as a warning. Other options: `tagPrefix
helper mounts the dashboard (SPA + `/api/*`) into your app.
```ts
-import { taskitoRouter, taskitoDashboard } from "taskito/contrib/express"; // peer: express
+import { taskitoRouter, taskitoDashboard } from "@byteveda/taskito/contrib/express"; // peer: express
app.use("/tasks", taskitoRouter(queue)); // POST /enqueue, GET /stats, /jobs/:id, ...
app.use("/admin", taskitoDashboard(queue)); // dashboard SPA + /api/*
-import { taskitoFastify, taskitoDashboardPlugin } from "taskito/contrib/fastify"; // peer: fastify
+import { taskitoFastify, taskitoDashboardPlugin } from "@byteveda/taskito/contrib/fastify"; // peer: fastify
app.register(taskitoFastify, { queue, prefix: "/tasks" });
app.register(taskitoDashboardPlugin, { queue, prefix: "/admin" });
```
@@ -449,7 +449,7 @@ and `resultTimeoutMs`.
NestJS exposes an injectable service:
```ts
-import { TaskitoModule, TaskitoService } from "taskito/contrib/nest"; // peers: @nestjs/common, reflect-metadata
+import { TaskitoModule, TaskitoService } from "@byteveda/taskito/contrib/nest"; // peers: @nestjs/common, reflect-metadata
@Module({ imports: [TaskitoModule.forRoot(queue)] })
export class AppModule {}
diff --git a/sdks/node/package.json b/sdks/node/package.json
index 29de4707..cd383143 100644
--- a/sdks/node/package.json
+++ b/sdks/node/package.json
@@ -1,5 +1,5 @@
{
- "name": "taskito",
+ "name": "@byteveda/taskito",
"version": "0.16.3",
"description": "Rust-powered task queue for Node.js — no broker required.",
"license": "MIT",