docs: update portal for WRNexusJS 0.8.0

This commit is contained in:
2026-08-02 23:57:41 +05:30
parent 9366895f78
commit 8d5d4b8f12
183 changed files with 14433 additions and 2492 deletions
+185 -6
View File
@@ -10,11 +10,11 @@ page wrnexusuploader {
<header class="topbar">
<a class="brand" href="/"><span>W</span> WRNexusJS</a>
<nav aria-label="Primary"><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/language">Language</a><a href="/architecture">Architecture</a></nav>
<div class="topbar-actions"><a class="preview-pill" href="/access">Private preview · v0.7.0</a><button data-wire-theme-toggle class="theme-button" aria-label="Toggle color theme" title="Toggle color theme">◐</button></div>
<div class="topbar-actions"><a class="preview-pill" href="/access">Private preview · v0.8.0</a><button data-wire-theme-toggle class="theme-button" aria-label="Toggle color theme" title="Toggle color theme">◐</button></div>
</header>
<div class="mobile-doc-nav"><details><summary>Browse documentation</summary><nav><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/language">Language</a><a href="/architecture">Architecture</a><a href="/tutorial">Tutorial</a><a href="/guides/project-structure">Guides</a><a href="/examples">Examples</a><a href="/search">Search</a></nav></details></div>
<main class="portal-main docs-layout">
<article id="main" class="documentation prose standalone package-document"><nav class="breadcrumbs" aria-label="Breadcrumb"><a href="/">Home</a><span>/</span><a href="/packages">Packages</a><span>/</span><span aria-current="page">@wrnexus/uploader</span></nav><section class="doc-intro"><span class="eyebrow">Data · Package reference</span><h1>@wrnexus/uploader</h1><p>Validated local/S3 uploads and secure file serving.</p><div class="doc-meta"><span>v0.7.0</span><span>Private registry</span><span>Data</span></div><section id="access" class="access-callout"><h2>Install the package</h2><p>After WorkRoot approves private registry access, install the release-aligned package:</p><pre><code>bun add @wrnexus/uploader@0.7.0</code><button type="button" class="copy-button" aria-label="Copy installation command">Copy</button></pre><p><a href="/access">Request preview access</a>. Never put registry tokens in source control.</p></section></section><section id="guide"><p>Config-driven file uploads + serving for <a href="https://www.npmjs.com/org/wrnexus" rel="noreferrer">WRNexusJS</a>. Declare named <strong>storage stores</strong> (local disk or any S3-compatible backend) in <code>wrnexus.config.ts</code>, upload with one function call, drop a drag-and-drop widget on a page, and serve files back — public or private. Zero external dependencies (S3 is signed with a built-in AWS SigV4 implementation, like the rest of the framework).</p>
<article id="main" class="documentation prose standalone package-document"><nav class="breadcrumbs" aria-label="Breadcrumb"><a href="/">Home</a><span>/</span><a href="/packages">Packages</a><span>/</span><span aria-current="page">@wrnexus/uploader</span></nav><section class="doc-intro"><span class="eyebrow">Data · Package reference</span><h1>@wrnexus/uploader</h1><p>Validated local/S3 uploads and secure file serving.</p><div class="doc-meta"><span>v0.8.0</span><span>Private registry</span><span>Data</span></div><section id="access" class="access-callout"><h2>Install the package</h2><p>After WorkRoot approves private registry access, install the release-aligned package:</p><pre><code>bun add @wrnexus/uploader@0.8.0</code><button type="button" class="copy-button" aria-label="Copy installation command">Copy</button></pre><p><a href="/access">Request preview access</a>. Never put registry tokens in source control.</p></section></section><section id="guide"><p>Config-driven file uploads + serving for <a href="https://www.npmjs.com/org/wrnexus" rel="noreferrer">WRNexusJS</a>. Declare named <strong>storage stores</strong> (local disk or any S3-compatible backend) in <code>wrnexus.config.ts</code>, upload with one function call, drop a drag-and-drop widget on a page, and serve files back — public or private. Zero external dependencies (S3 is signed with a built-in AWS SigV4 implementation, like the rest of the framework).</p>
<h3 id="usage">Usage</h3>
<h4 id="configure-local-and-s3-stores">Configure local and S3 stores</h4>
<pre data-language="ts"><code>// wrnexus.config.ts
@@ -88,6 +88,7 @@ await getStore(&quot;docs&quot;).driver.delete(files[0].key);</code></pre>
import &#123; serveFromStore &#125; from &quot;@wrnexus/uploader&quot;;
export const GET = serveFromStore(&quot;docs&quot;); // your middleware decides who gets in</code></pre>
<h3 id="api">API</h3>
<p>Uploads can participate in security and media pipelines without changing storage drivers. Pass a <code>scan</code> hook to reject malware/DLP findings before storage, and <code>afterStore</code> to enqueue image/video processing or indexing. If post-processing throws, WRNexus deletes the newly written object so a partially accepted upload is never left behind.</p>
<div class="table-wrap"><table>
<thead><tr><th>Export</th><th>What</th></tr></thead>
<tbody><tr><td><code>handleUpload(opts)</code></td><td>POST route handler → JSON <code>&#123; ok, files &#125;</code></td></tr><tr><td><code>upload(store, req, opts)</code></td><td>Parse + validate + store; returns <code>&#123; files &#125;</code></td></tr><tr><td><code>serveFromStore(store)</code></td><td>Route handler that streams an object back (gate it for private)</td></tr><tr><td><code>getStore(name?)</code> / <code>hasStorage(name?)</code></td><td>Reach a store's <code>driver</code> (<code>put</code>/<code>get</code>/<code>delete</code>/<code>publicUrl</code>)</td></tr><tr><td><code>configureStorage(config, root)</code></td><td>Build the registry (the framework calls this at startup)</td></tr><tr><td><code>s3Driver</code> / <code>localDriver</code> / <code>signS3</code></td><td>Lower-level building blocks</td></tr></tbody></table></div>
@@ -97,7 +98,28 @@ export const GET = serveFromStore(&quot;docs&quot;); // your middleware decides
<li>SigV4 signing is implemented from scratch (no <code>@aws-sdk</code>); tested against local S3 semantics.</li>
<p>Live AWS/R2 connectivity depends on your credentials + bucket policy.</p>
<li>v1 buffers each file in memory up to its size cap (fine for images/docs up to tens of MB).</li>
</ul></section><section id="api" class="api"><h2>Complete TypeScript API</h2><p>Generated from the exact installed package declarations.</p><pre data-language="typescript"><code>import &#123; Context &#125; from '@wrnexus/core';
</ul>
<h3 id="helper-and-component-kit">Helper and component kit</h3>
<p>Use <code>formatFileSize</code>, <code>uploadAccept</code>, <code>uploadedFileMap</code>, <code>uploaderAttributes</code>, and <code>assertUploadedFiles</code> to keep upload forms and server validation consistent.</p>
<p>Enable <code>uploaderPlugin()</code> for:</p>
<ul>
<li><code>&lt;UploadDropzone /&gt;</code></li>
<li><code>&lt;UploadStatus /&gt;</code></li>
</ul>
<p>The complete blocks compose <code>Card</code>, <code>Alert</code>, and <code>Badge</code> from <code>@wrnexus/ui</code>; the specialized upload runtime remains responsible for the native file input and secure transport behavior. Large files can use <code>createResumableUploadManager</code>. Sessions are bounded and expiring; chunks may arrive out of order, carry SHA-256 checksums, and are idempotent when retried. Conflicting retries reject, and the object is assembled only after every exact-sized chunk is present.</p>
<pre data-language="ts"><code>const uploads = createResumableUploadManager(&#123;
driver: getStore(&quot;documents&quot;).driver,
sessions: redisUploadSessionStore,
chunkSize: 5 * 1024 * 1024,
maxBytes: 500 * 1024 * 1024,
accept: [&quot;application/pdf&quot;],
&#125;);
const session = await uploads.create(&#123; name: &quot;report.pdf&quot;, size, type &#125;);
await uploads.uploadChunk(session.id, index, bytes, sha256);</code></pre>
<p>The included memory session store is intended for one-process apps and tests. Multi-instance production deployments should implement <code>ResumableSessionStore</code> with shared durable storage and atomic session updates, and periodically call <code>prune()</code> for abandoned uploads.</p></section><section id="api" class="api"><h2>Complete TypeScript API</h2><p>Generated from the exact installed package declarations.</p><pre data-language="typescript"><code>import &#123; Context &#125; from '@wrnexus/core';
export &#123; UploaderPluginOptions, uploaderComponentsDir, default as uploaderPlugin &#125; from './plugin.js';
import '@wrnexus/plugin';
/**
* Storage driver contract + config types.
@@ -227,6 +249,25 @@ interface UploadOptions &#123;
accept?: string[];
/** Key prefix, e.g. `&quot;avatars&quot;` → keys become `avatars/&lt;yyyy&gt;/&lt;mm&gt;/&lt;rand&gt;.&lt;ext&gt;`. */
prefix?: string;
/** Virus/DLP/content scanner invoked before bytes enter storage. Throw or return unsafe to reject. */
scan?: (file: UploadScanInput) =&gt; UploadScanResult | Promise&lt;UploadScanResult&gt;;
/** Image/video/indexing hook invoked after storage. Failure removes the just-written object. */
afterStore?: (file: UploadedFile &amp; &#123;
bytes: Uint8Array;
store: Store;
&#125;) =&gt; void | Promise&lt;void&gt;;
&#125;
interface UploadScanInput &#123;
name: string;
type: string;
size: number;
bytes: Uint8Array;
store: Store;
&#125;
interface UploadScanResult &#123;
safe: boolean;
reason?: string;
scanner?: string;
&#125;
/** A 4xx-carrying error so `handleUpload` can map it to a status. */
declare class UploadError extends Error &#123;
@@ -401,7 +442,145 @@ interface SignedFileToken &#123;
declare function createSignedFileToken(input: SignedFileToken, secret: string): Promise&lt;string&gt;;
declare function verifySignedFileToken(token: string, secret: string, now?: number): Promise&lt;SignedFileToken | null&gt;;
export &#123; type LocalStoreConfig, type PutMeta, type S3StoreConfig, type SignedFileToken, type StorageConfig, type StorageDriver, type Store, type StoreAccess, type StoreConfig, type StoredObject, UPLOADS_PREFIX, UPLOAD_JS_HREF, UPLOAD_RUNTIME, UploadError, type UploadInspection, type UploadOptions, type UploadPolicy, UploadPolicyError, type UploadedFile, accepts, configureStorage, contentTypeOf, createSignedFileToken, encodeKey, enforceUploadPolicy, extForType, extOf, getStore, handleUpload, hasStorage, inspectUpload, localDriver, s3Driver, safeObjectKey, serveFromStore, serveStoredFile, sha256Hex, signS3, sniffContentType, storeNames, storedUrl, upload, verifySignedFileToken &#125;;
declare function formatFileSize(bytes: number, locale?: string): string;
declare function uploadAccept(value: string | readonly string[]): string;
declare function uploadedFileMap(files: readonly UploadedFile[]): Record&lt;string, UploadedFile&gt;;
declare function uploaderAttributes(options?: &#123;
store?: string;
endpoint?: string;
accept?: string | readonly string[];
maxBytes?: number;
multiple?: boolean;
field?: string;
label?: string;
&#125;): Record&lt;string, string | boolean&gt;;
declare function assertUploadedFiles(files: readonly UploadedFile[], options?: &#123;
min?: number;
max?: number;
&#125;): readonly UploadedFile[];
interface ResumableUploadSession &#123;
id: string;
key: string;
name: string;
type: string;
size: number;
chunkSize: number;
totalChunks: number;
createdAt: number;
expiresAt: number;
chunks: Record&lt;number, Uint8Array&gt;;
digests: Record&lt;number, string&gt;;
&#125;
interface ResumableSessionStore &#123;
get(id: string): Promise&lt;ResumableUploadSession | null&gt;;
put(session: ResumableUploadSession): Promise&lt;void&gt;;
delete(id: string): Promise&lt;void&gt;;
list(): Promise&lt;ResumableUploadSession[]&gt;;
&#125;
declare function memoryResumableSessionStore(): ResumableSessionStore;
interface ResumableUploadManagerOptions &#123;
driver: StorageDriver;
sessions?: ResumableSessionStore;
maxBytes?: number;
chunkSize?: number;
maxSessions?: number;
ttlMs?: number;
accept?: string[];
prefix?: string;
publicUrl?: (key: string) =&gt; string | null;
now?: () =&gt; number;
&#125;
interface CreateResumableUpload &#123;
name: string;
type?: string;
size: number;
chunkSize?: number;
&#125;
interface ResumableChunkResult &#123;
receivedChunks: number;
totalChunks: number;
complete: boolean;
file?: UploadedFile;
&#125;
interface ResumableUploadManager &#123;
create(input: CreateResumableUpload): Promise&lt;ResumableUploadSession&gt;;
uploadChunk(id: string, index: number, data: Uint8Array, sha256?: string): Promise&lt;ResumableChunkResult&gt;;
status(id: string): Promise&lt;&#123;
received: number[];
totalChunks: number;
expiresAt: number;
&#125; | null&gt;;
cancel(id: string): Promise&lt;boolean&gt;;
prune(): Promise&lt;number&gt;;
&#125;
declare function createResumableUploadManager(options: ResumableUploadManagerOptions): ResumableUploadManager;
interface QuotaUsage &#123;
owner: string;
bytes: number;
objects: number;
updatedAt: number;
&#125;
interface QuotaStore &#123;
get(owner: string): Promise&lt;QuotaUsage&gt;;
reserve(owner: string, bytes: number, limits: &#123;
bytes: number;
objects?: number;
&#125;): Promise&lt;boolean&gt;;
release(owner: string, bytes: number): Promise&lt;void&gt;;
&#125;
declare function memoryQuotaStore(): QuotaStore;
interface QuotaSqlClient &#123;
query&lt;T = any&gt;(sql: string, parameters?: unknown[]): Promise&lt;&#123;
rows: T[];
&#125;&gt;;
&#125;
/** PostgreSQL quota accounting using a single atomic conditional upsert. */
declare function postgresQuotaStore(db: QuotaSqlClient, table?: string): QuotaStore;
declare const POSTGRES_QUOTA_SCHEMA = &quot;CREATE TABLE IF NOT EXISTS wrnexus_storage_quota (owner text PRIMARY KEY, bytes bigint NOT NULL DEFAULT 0, objects integer NOT NULL DEFAULT 0, updated_at bigint NOT NULL);&quot;;
interface MultipartObjectClient &#123;
create(key: string, meta: PutMeta): Promise&lt;string&gt;;
uploadPart(uploadId: string, key: string, part: number, bytes: Uint8Array): Promise&lt;string&gt;;
complete(uploadId: string, key: string, parts: Array&lt;&#123;
part: number;
etag: string;
&#125;&gt;): Promise&lt;void&gt;;
abort(uploadId: string, key: string): Promise&lt;void&gt;;
&#125;
declare function multipartUpload(client: MultipartObjectClient, key: string, bytes: Uint8Array, meta: PutMeta, options?: &#123;
partBytes?: number;
concurrency?: number;
&#125;): Promise&lt;void&gt;;
interface TemporaryObject &#123;
key: string;
expiresAt: number;
&#125;
declare function createTemporaryObjectCleaner(driver: StorageDriver, options?: &#123;
now?: () =&gt; number;
limit?: number;
&#125;): &#123;
track(key: string, ttlMs: number): void;
cleanup(at?: number): Promise&lt;number&gt;;
snapshot: () =&gt; &#123;
tracked: number;
nextExpiry: number | undefined;
&#125;;
&#125;;
interface VideoTranscodeOptions &#123;
format: &quot;mp4&quot; | &quot;webm&quot;;
width?: number;
height?: number;
videoBitrateKbps?: number;
&#125;
declare function ffmpegVideoTranscoder(options?: &#123;
executable?: string;
spawn?: (args: string[]) =&gt; &#123;
exited: Promise&lt;number&gt;;
&#125;;
&#125;): (input: string, output: string, config: VideoTranscodeOptions) =&gt; Promise&lt;void&gt;;
export &#123; type CreateResumableUpload, type LocalStoreConfig, type MultipartObjectClient, POSTGRES_QUOTA_SCHEMA, type PutMeta, type QuotaSqlClient, type QuotaStore, type QuotaUsage, type ResumableChunkResult, type ResumableSessionStore, type ResumableUploadManager, type ResumableUploadManagerOptions, type ResumableUploadSession, type S3StoreConfig, type SignedFileToken, type StorageConfig, type StorageDriver, type Store, type StoreAccess, type StoreConfig, type StoredObject, type TemporaryObject, UPLOADS_PREFIX, UPLOAD_JS_HREF, UPLOAD_RUNTIME, UploadError, type UploadInspection, type UploadOptions, type UploadPolicy, UploadPolicyError, type UploadScanInput, type UploadScanResult, type UploadedFile, type VideoTranscodeOptions, accepts, assertUploadedFiles, configureStorage, contentTypeOf, createResumableUploadManager, createSignedFileToken, createTemporaryObjectCleaner, encodeKey, enforceUploadPolicy, extForType, extOf, ffmpegVideoTranscoder, formatFileSize, getStore, handleUpload, hasStorage, inspectUpload, localDriver, memoryQuotaStore, memoryResumableSessionStore, multipartUpload, postgresQuotaStore, s3Driver, safeObjectKey, serveFromStore, serveStoredFile, sha256Hex, signS3, sniffContentType, storeNames, storedUrl, upload, uploadAccept, uploadedFileMap, uploaderAttributes, verifySignedFileToken &#125;;
</code></pre></section><section id="examples" class="examples"><h2>Examples</h2><p>Copy-ready examples from the installed package documentation.</p><div class="example-grid"><article class="example-card"><h3>Configure local and S3 stores</h3><pre data-language="ts"><code>// wrnexus.config.ts
import type &#123; AppConfig &#125; from &quot;@wrnexus/styles&quot;;
@@ -451,9 +630,9 @@ await getStore(&quot;docs&quot;).driver.delete(files[0].key);</code></pre></arti
&gt;&lt;/div&gt;</code></pre></article><article class="example-card"><h3>Serve private files behind application authentication</h3><pre data-language="ts"><code>// app/api/files/[key].ts
import &#123; serveFromStore &#125; from &quot;@wrnexus/uploader&quot;;
export const GET = serveFromStore(&quot;docs&quot;); // your middleware decides who gets in</code></pre></article></div></section></article>
<aside class="on-this-page"><h2>On this page</h2><nav><a class="toc-level-2" href="#guide">Guide</a><a class="toc-level-3" href="#usage">Usage</a><a class="toc-level-4" href="#configure-local-and-s3-stores">Configure local and S3 stores</a><a class="toc-level-4" href="#upload-from-an-api-route-or-server-function">Upload from an API route or server function</a><a class="toc-level-4" href="#add-a-client-upload-widget">Add a client upload widget</a><a class="toc-level-4" href="#serve-private-files-behind-application-authentication">Serve private files behind application authentication</a><a class="toc-level-3" href="#api">API</a><a class="toc-level-3" href="#notes">Notes</a><a class="toc-level-2" href="#api">Complete API</a><a class="toc-level-2" href="#examples">Examples</a></nav></aside>
<aside class="on-this-page"><h2>On this page</h2><nav><a class="toc-level-2" href="#guide">Guide</a><a class="toc-level-3" href="#usage">Usage</a><a class="toc-level-4" href="#configure-local-and-s3-stores">Configure local and S3 stores</a><a class="toc-level-4" href="#upload-from-an-api-route-or-server-function">Upload from an API route or server function</a><a class="toc-level-4" href="#add-a-client-upload-widget">Add a client upload widget</a><a class="toc-level-4" href="#serve-private-files-behind-application-authentication">Serve private files behind application authentication</a><a class="toc-level-3" href="#api">API</a><a class="toc-level-3" href="#notes">Notes</a><a class="toc-level-3" href="#helper-and-component-kit">Helper and component kit</a><a class="toc-level-2" href="#api">Complete API</a><a class="toc-level-2" href="#examples">Examples</a></nav></aside>
</main>
<footer><div class="footer-brand"><span class="footer-mark" aria-hidden="true">W</span><p><strong>WRNexusJS 0.7.0</strong><span>Complete API documentation generated from installed package declarations.</span></p></div><nav aria-label="Footer"><a href="/packages">All packages</a><a href="/getting-started">Get started</a><a href="/security">Security</a><a href="/support">Support</a><a href="/llms.txt">AI guide</a></nav><p class="footer-meta">Private Developer Preview · Bun-native</p></footer>
<footer><div class="footer-brand"><span class="footer-mark" aria-hidden="true">W</span><p><strong>WRNexusJS 0.8.0</strong><span>Complete API documentation generated from installed package declarations.</span></p></div><nav aria-label="Footer"><a href="/packages">All packages</a><a href="/getting-started">Get started</a><a href="/security">Security</a><a href="/support">Support</a><a href="/llms.txt">AI guide</a></nav><p class="footer-meta">Private Developer Preview · Bun-native</p></footer>
<BackToTop />
</div>
}