release: WRNexusJS 0.2.29
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ai",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/authz",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -329,6 +329,16 @@ const MIGRATIONS: Migration[] = [
|
||||
// No project file migration is required for this framework release.
|
||||
},
|
||||
},
|
||||
{
|
||||
version: "0.2.29",
|
||||
id: "workspace-config-improvements",
|
||||
description:
|
||||
"Adds environment-aware workspace domains, app URL helpers, component tag syntax, layouts, and editor improvements.",
|
||||
apply() {
|
||||
// No generated project files require automatic changes.
|
||||
// Existing applications remain compatible with this release.
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/** Release tooling uses this to require an explicit migration entry per version. */
|
||||
|
||||
+214
-16
@@ -19,17 +19,44 @@ import type { GatewayAuth, GatewaySecurity } from "@wrnexus/dev-server";
|
||||
|
||||
const frameworkVersion = currentCliVersion();
|
||||
|
||||
export type WorkspaceEnvironment = "development" | "staging" | "production" | (string & {});
|
||||
|
||||
export interface WorkspaceEnvironmentConfig {
|
||||
protocol?: "http" | "https";
|
||||
rootDomain?: string;
|
||||
port?: number;
|
||||
}
|
||||
|
||||
export interface WorkspaceApp {
|
||||
name: string;
|
||||
dir: string;
|
||||
domains: string[];
|
||||
|
||||
/**
|
||||
* Generates <subdomain>.<environment.rootDomain>.
|
||||
* Example: subdomain "sso" + rootDomain "local.wrnexus.test".
|
||||
*/
|
||||
subdomain?: string;
|
||||
|
||||
/**
|
||||
* Explicit hostname overrides by environment.
|
||||
*/
|
||||
domains?: string[] | Partial<Record<WorkspaceEnvironment, string | string[]>>;
|
||||
|
||||
/**
|
||||
* Complete public URL override by environment.
|
||||
*/
|
||||
urls?: Partial<Record<WorkspaceEnvironment, string>>;
|
||||
|
||||
port?: number;
|
||||
/** Per-app access control enforced at the gateway (basic auth, IP allowlist, forward-auth). */
|
||||
auth?: GatewayAuth;
|
||||
}
|
||||
|
||||
export interface WorkspaceConfig {
|
||||
defaultEnvironment?: WorkspaceEnvironment;
|
||||
|
||||
environments?: Record<WorkspaceEnvironment, WorkspaceEnvironmentConfig>;
|
||||
|
||||
apps: WorkspaceApp[];
|
||||
/** Gateway-wide security (trusted hosts, rate limit, headers, access log). */
|
||||
security?: GatewaySecurity;
|
||||
}
|
||||
|
||||
@@ -263,7 +290,13 @@ export async function addWorkspaceApp(root: string, name: string, args: string[]
|
||||
if (config.apps.some((app) => app.name === name || app.dir.replace(/\\/g, "/") === dir)) {
|
||||
throw new Error(`Workspace app '${name}' already exists.`);
|
||||
}
|
||||
if (config.apps.some((app) => app.domains.includes(domain))) {
|
||||
const normalizedDomain = domain.toLowerCase();
|
||||
|
||||
if (
|
||||
config.apps.some((app) =>
|
||||
configuredDomains(app).some((configured) => configured.toLowerCase() === normalizedDomain),
|
||||
)
|
||||
) {
|
||||
throw new Error(`Workspace domain '${domain}' is already assigned.`);
|
||||
}
|
||||
const appRoot = join(resolvedRoot, "apps", name);
|
||||
@@ -285,6 +318,24 @@ export async function addWorkspaceApp(root: string, name: string, args: string[]
|
||||
console.log("\nRun `bun install`, then `bun run dev`.");
|
||||
}
|
||||
|
||||
function configuredDomains(app: WorkspaceApp): string[] {
|
||||
if (!app.domains) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (Array.isArray(app.domains)) {
|
||||
return app.domains;
|
||||
}
|
||||
|
||||
return Object.values(app.domains).flatMap((value) => {
|
||||
if (!value) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return Array.isArray(value) ? value : [value];
|
||||
});
|
||||
}
|
||||
|
||||
/** Scaffold a monorepo workspace with two starter apps + a shared package. */
|
||||
export function createWorkspace(name: string): void {
|
||||
if (!name) {
|
||||
@@ -329,24 +380,171 @@ export async function loadWorkspaceConfig(root: string): Promise<WorkspaceConfig
|
||||
/** Run the multi-app gateway from `wrnexus.workspace.ts`. */
|
||||
export async function runGateway(root: string, args: string[]): Promise<void> {
|
||||
const config = await loadWorkspaceConfig(resolve(root));
|
||||
const portArg = args.find((a) => a.startsWith("--port="));
|
||||
const hostArg = args.find((a) => a.startsWith("--host="));
|
||||
const port = portArg ? Number(portArg.split("=")[1]) : 3000;
|
||||
|
||||
const portArg = args.find((arg) => arg.startsWith("--port="));
|
||||
|
||||
const hostArg = args.find((arg) => arg.startsWith("--host="));
|
||||
|
||||
const environmentArg = args.find((arg) => arg.startsWith("--environment="));
|
||||
|
||||
const profileArg = args.find((arg) => arg.startsWith("--profile="));
|
||||
|
||||
const environment =
|
||||
environmentArg?.split("=")[1] ||
|
||||
profileArg?.split("=")[1] ||
|
||||
process.env.WRNEXUS_ENV ||
|
||||
process.env.WRNEXUS_PROFILE ||
|
||||
config.defaultEnvironment ||
|
||||
(args.includes("--prod") ? "production" : "development");
|
||||
|
||||
const resolved = resolveWorkspaceConfig(config, environment);
|
||||
|
||||
const port = portArg
|
||||
? Number(portArg.split("=")[1])
|
||||
: resolved.environment === "development"
|
||||
? 3000
|
||||
: 80;
|
||||
|
||||
const hostname = hostArg?.split("=")[1];
|
||||
const mode = args.includes("--prod") ? "production" : "development";
|
||||
|
||||
const { startGateway } = await import("@wrnexus/dev-server");
|
||||
|
||||
await startGateway({
|
||||
port,
|
||||
hostname,
|
||||
mode,
|
||||
security: config.security,
|
||||
apps: config.apps.map((a) => ({
|
||||
name: a.name,
|
||||
dir: resolve(root, a.dir),
|
||||
domains: a.domains,
|
||||
port: a.port,
|
||||
auth: a.auth,
|
||||
mode: environment === "production" ? "production" : "development",
|
||||
environment,
|
||||
security: resolved.security,
|
||||
apps: resolved.apps.map((app) => ({
|
||||
name: app.name,
|
||||
dir: resolve(root, app.dir),
|
||||
domains: app.domains,
|
||||
publicOrigin: app.publicOrigin,
|
||||
port: app.port,
|
||||
auth: app.auth,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
function environmentVariableName(appName: string): string {
|
||||
return `WRNEXUS_APP_${appName.replace(/[^A-Za-z0-9]/g, "_").toUpperCase()}_URL`;
|
||||
}
|
||||
|
||||
function normalizeOrigin(value: string): string {
|
||||
const url = new URL(value);
|
||||
|
||||
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
||||
throw new Error(`Application URL must use http or https: ${value}`);
|
||||
}
|
||||
|
||||
return url.origin;
|
||||
}
|
||||
|
||||
function valuesForEnvironment(
|
||||
value: WorkspaceApp["domains"],
|
||||
environment: WorkspaceEnvironment,
|
||||
): string[] {
|
||||
if (!value) return [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const selected = value[environment];
|
||||
|
||||
if (!selected) return [];
|
||||
|
||||
return Array.isArray(selected) ? selected : [selected];
|
||||
}
|
||||
|
||||
export interface ResolvedWorkspaceApp extends WorkspaceApp {
|
||||
domains: string[];
|
||||
publicOrigin: string;
|
||||
}
|
||||
|
||||
export interface ResolvedWorkspaceConfig {
|
||||
environment: WorkspaceEnvironment;
|
||||
apps: ResolvedWorkspaceApp[];
|
||||
security?: GatewaySecurity;
|
||||
}
|
||||
|
||||
export function resolveWorkspaceConfig(
|
||||
config: WorkspaceConfig,
|
||||
environment: WorkspaceEnvironment,
|
||||
): ResolvedWorkspaceConfig {
|
||||
const environmentConfig = config.environments?.[environment] ?? {};
|
||||
|
||||
const protocol = environmentConfig.protocol ?? (environment === "production" ? "https" : "http");
|
||||
|
||||
const configuredPort = environmentConfig.port;
|
||||
|
||||
const apps = config.apps.map((app) => {
|
||||
const envOverride = process.env[environmentVariableName(app.name)];
|
||||
|
||||
const configuredUrl = app.urls?.[environment];
|
||||
|
||||
const explicitDomains = valuesForEnvironment(app.domains, environment);
|
||||
|
||||
const generatedDomain =
|
||||
app.subdomain && environmentConfig.rootDomain
|
||||
? `${app.subdomain}.${environmentConfig.rootDomain}`
|
||||
: undefined;
|
||||
|
||||
const domains =
|
||||
explicitDomains.length > 0 ? explicitDomains : generatedDomain ? [generatedDomain] : [];
|
||||
|
||||
let publicOrigin: string;
|
||||
|
||||
if (envOverride) {
|
||||
publicOrigin = normalizeOrigin(envOverride);
|
||||
} else if (configuredUrl) {
|
||||
publicOrigin = normalizeOrigin(configuredUrl);
|
||||
} else if (domains[0]) {
|
||||
const port =
|
||||
configuredPort &&
|
||||
!(
|
||||
(protocol === "http" && configuredPort === 80) ||
|
||||
(protocol === "https" && configuredPort === 443)
|
||||
)
|
||||
? `:${configuredPort}`
|
||||
: "";
|
||||
|
||||
publicOrigin = `${protocol}://${domains[0]}${port}`;
|
||||
} else {
|
||||
throw new Error(
|
||||
`No domain or URL configured for workspace app "${app.name}" in environment "${environment}".`,
|
||||
);
|
||||
}
|
||||
|
||||
const publicUrl = new URL(publicOrigin);
|
||||
|
||||
return {
|
||||
...app,
|
||||
domains: domains.length > 0 ? domains : [publicUrl.hostname],
|
||||
publicOrigin,
|
||||
};
|
||||
});
|
||||
|
||||
const usedDomains = new Map<string, string>();
|
||||
|
||||
for (const app of apps) {
|
||||
for (const domain of app.domains) {
|
||||
const normalized = domain.toLowerCase();
|
||||
const owner = usedDomains.get(normalized);
|
||||
|
||||
if (owner) {
|
||||
throw new Error(
|
||||
`Workspace domain "${domain}" is assigned to both "${owner}" and "${app.name}".`,
|
||||
);
|
||||
}
|
||||
|
||||
usedDomains.set(normalized, app.name);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
environment,
|
||||
apps,
|
||||
security: config.security,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/core",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/db",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -35,6 +35,7 @@ export interface GatewayApp {
|
||||
dir: string;
|
||||
/** Host names routed to this app (e.g. ["localhost", "web.localhost"]). */
|
||||
domains: string[];
|
||||
publicOrigin?: string;
|
||||
/** Optional fixed internal port; otherwise assigned from the gateway port. */
|
||||
port?: number;
|
||||
/** Access control enforced at the edge for this app. */
|
||||
@@ -59,6 +60,7 @@ export interface GatewayOptions {
|
||||
port?: number;
|
||||
hostname?: string;
|
||||
mode?: "development" | "production";
|
||||
environment?: string;
|
||||
apps: GatewayApp[];
|
||||
security?: GatewaySecurity;
|
||||
}
|
||||
@@ -79,7 +81,7 @@ interface WsBridge {
|
||||
origin: string;
|
||||
path: string;
|
||||
backend?: WebSocket;
|
||||
queue: (string | ArrayBufferLike | ArrayBufferView)[];
|
||||
queue: Array<string | ArrayBuffer>;
|
||||
}
|
||||
|
||||
/** Decide whether a gateway child should be relaunched after it exits. */
|
||||
@@ -262,6 +264,11 @@ export async function startGateway(opts: GatewayOptions): Promise<RunningGateway
|
||||
const port = opts.port ?? 3000;
|
||||
const mode = opts.mode ?? "development";
|
||||
const hostname = opts.hostname ?? defaultGatewayHostname(mode);
|
||||
const environment = opts.environment ?? (mode === "production" ? "production" : "development");
|
||||
|
||||
const workspaceOrigins = Object.fromEntries(
|
||||
opts.apps.map((app) => [app.name, app.publicOrigin ?? `http://${app.domains[0]}:${port}`]),
|
||||
);
|
||||
const displayHost = hostname === "0.0.0.0" || hostname === "::" ? "localhost" : hostname;
|
||||
const serveEntry = fileURLToPath(import.meta.resolve("@wrnexus/dev-server/serve-entry"));
|
||||
|
||||
@@ -281,12 +288,28 @@ export async function startGateway(opts: GatewayOptions): Promise<RunningGateway
|
||||
mode === "production"
|
||||
? spawn(process.execPath, [join(dir, "dist", "server.js")], {
|
||||
stdio: "inherit",
|
||||
env: { ...process.env, PORT: String(appPort) },
|
||||
env: {
|
||||
...process.env,
|
||||
PORT: String(appPort),
|
||||
WRNEXUS_ENV: environment,
|
||||
WRNEXUS_APP_NAME: app.name,
|
||||
WRNEXUS_APP_ORIGIN: app.publicOrigin ?? `http://${app.domains[0]}:${port}`,
|
||||
WRNEXUS_WORKSPACE_ORIGINS: JSON.stringify(workspaceOrigins),
|
||||
},
|
||||
})
|
||||
: spawn(
|
||||
process.execPath,
|
||||
[serveEntry, join(dir, "app"), String(appPort), mode, "127.0.0.1"],
|
||||
{ stdio: "inherit" },
|
||||
{
|
||||
stdio: "inherit",
|
||||
env: {
|
||||
...process.env,
|
||||
WRNEXUS_ENV: environment,
|
||||
WRNEXUS_APP_NAME: app.name,
|
||||
WRNEXUS_APP_ORIGIN: app.publicOrigin ?? `http://${app.domains[0]}:${port}`,
|
||||
WRNEXUS_WORKSPACE_ORIGINS: JSON.stringify(workspaceOrigins),
|
||||
},
|
||||
},
|
||||
);
|
||||
target.child = child;
|
||||
|
||||
@@ -415,14 +438,60 @@ export async function startGateway(opts: GatewayOptions): Promise<RunningGateway
|
||||
for (const m of ws.data.queue) backend.send(m);
|
||||
ws.data.queue = [];
|
||||
});
|
||||
backend.addEventListener("message", (e) => ws.send(e.data as string | ArrayBufferLike));
|
||||
backend.addEventListener("message", async (event) => {
|
||||
const data = event.data;
|
||||
|
||||
if (typeof data === "string") {
|
||||
ws.send(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data instanceof Blob) {
|
||||
const buffer = await data.arrayBuffer();
|
||||
ws.send(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data instanceof ArrayBuffer) {
|
||||
ws.send(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ArrayBuffer.isView(data)) {
|
||||
const buffer = data.buffer.slice(
|
||||
data.byteOffset,
|
||||
data.byteOffset + data.byteLength,
|
||||
) as ArrayBuffer;
|
||||
|
||||
ws.send(buffer);
|
||||
}
|
||||
});
|
||||
backend.addEventListener("close", () => ws.close());
|
||||
backend.addEventListener("error", () => ws.close());
|
||||
},
|
||||
message(ws, message) {
|
||||
let data: string | ArrayBuffer;
|
||||
|
||||
if (typeof message === "string") {
|
||||
data = message;
|
||||
} else if (message instanceof ArrayBuffer) {
|
||||
data = message;
|
||||
} else {
|
||||
const view = message as ArrayBufferView;
|
||||
|
||||
data = view.buffer.slice(
|
||||
view.byteOffset,
|
||||
view.byteOffset + view.byteLength,
|
||||
) as ArrayBuffer;
|
||||
}
|
||||
|
||||
const backend = ws.data.backend;
|
||||
if (backend && backend.readyState === WebSocket.OPEN) backend.send(message);
|
||||
else ws.data.queue.push(message);
|
||||
|
||||
if (backend && backend.readyState === WebSocket.OPEN) {
|
||||
backend.send(data);
|
||||
} else {
|
||||
ws.data.queue.push(data);
|
||||
}
|
||||
},
|
||||
close(ws) {
|
||||
ws.data.backend?.close();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/encryption",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/helpers",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
||||
|
||||
@@ -136,3 +136,11 @@ export function redirectToLogin(
|
||||
target.searchParams.set(options.returnToParam ?? "returnTo", original.href);
|
||||
return Response.redirect(target, options.status ?? 302);
|
||||
}
|
||||
|
||||
export {
|
||||
appOrigin,
|
||||
appUrl,
|
||||
currentAppName,
|
||||
currentAppOrigin,
|
||||
workspaceAppOrigins,
|
||||
} from "./workspace.ts";
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
function workspaceOrigins(): Record<string, string> {
|
||||
const value = process.env.WRNEXUS_WORKSPACE_ORIGINS;
|
||||
|
||||
if (!value) {
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
|
||||
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return parsed as Record<string, string>;
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function normalizePath(path: string): string {
|
||||
if (!path) return "/";
|
||||
|
||||
return path.startsWith("/") ? path : `/${path}`;
|
||||
}
|
||||
|
||||
export function appOrigin(appName: string): string {
|
||||
const origins = workspaceOrigins();
|
||||
const origin = origins[appName];
|
||||
|
||||
if (!origin) {
|
||||
throw new Error(
|
||||
`Unknown workspace app "${appName}". Available apps: ${
|
||||
Object.keys(origins).join(", ") || "none"
|
||||
}.`,
|
||||
);
|
||||
}
|
||||
|
||||
return new URL(origin).origin;
|
||||
}
|
||||
|
||||
export function appUrl(appName: string, path = "/"): string {
|
||||
return new URL(normalizePath(path), `${appOrigin(appName)}/`).href;
|
||||
}
|
||||
|
||||
export function currentAppName(): string | undefined {
|
||||
return process.env.WRNEXUS_APP_NAME;
|
||||
}
|
||||
|
||||
export function currentAppOrigin(): string | undefined {
|
||||
const value = process.env.WRNEXUS_APP_ORIGIN;
|
||||
|
||||
return value ? new URL(value).origin : undefined;
|
||||
}
|
||||
|
||||
export function workspaceAppOrigins(): Readonly<Record<string, string>> {
|
||||
return Object.freeze({ ...workspaceOrigins() });
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/i18n",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/jwt",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/native",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/oauth",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/pubsub",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/queue",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/reactive",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/router",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ssr",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/styles",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/test",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/tracking",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/uploader",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/validation",
|
||||
"version": "0.2.28",
|
||||
"version": "0.2.29",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
Reference in New Issue
Block a user