@stacksjs/stx 0.2.150 → 0.2.152

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/dist/ssr.d.ts CHANGED
@@ -16,7 +16,7 @@ export declare function render(template: string, data?: Record<string, unknown>,
16
16
  /**
17
17
  * Create a STX server application
18
18
  */
19
- export declare function createApp(config?: AppConfig): void;
19
+ export declare function createApp(config?: AppConfig): StxServerApp;
20
20
  /** Session data store */
21
21
  export declare interface SessionData {
22
22
  [key: string]: unknown
@@ -87,6 +87,22 @@ export declare interface AppConfig {
87
87
  csrfEnabled?: boolean
88
88
  sessionStore?: SessionStore
89
89
  }
90
+ /**
91
+ * Handle returned by {@link createApp} — the server application surface.
92
+ */
93
+ export declare interface StxServerApp {
94
+ fetch: (request: Request) => Promise<Response>
95
+ get: (pattern: string, handler: RouteHandler, middleware?: Middleware[]) => StxServerApp
96
+ post: (pattern: string, handler: RouteHandler, middleware?: Middleware[]) => StxServerApp
97
+ put: (pattern: string, handler: RouteHandler, middleware?: Middleware[]) => StxServerApp
98
+ delete: (pattern: string, handler: RouteHandler, middleware?: Middleware[]) => StxServerApp
99
+ patch: (pattern: string, handler: RouteHandler, middleware?: Middleware[]) => StxServerApp
100
+ use: (middleware: Middleware) => StxServerApp
101
+ render: (template: string, data?: Record<string, unknown>, ctx?: RequestContext) => Promise<Response>
102
+ redirect: (url: string, status?: 302 | 301 | 303 | 307 | 308) => Response
103
+ back: (ctx: RequestContext, errors?: ValidationErrors, oldInput?: Record<string, string>) => Response
104
+ listen: (port?: number) => ReturnType<typeof Bun.serve>
105
+ }
90
106
  /** Route handler */
91
107
  // eslint-disable-next-line pickier/no-unused-vars
92
108
  export type RouteHandler = (ctx: RequestContext) => Response | Promise<Response>;
package/dist/utils.js CHANGED
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { extractAndStripCssImports, extractBridgeData, injectBrowserCoreAutoImports, processClientScript, renderVendorStyleTags } from "./client-script.js";
4
4
  import { COMPONENT_CLIENT_FACTORIES_CONTEXT_KEY, registerComponentClientFactory } from "./component-client-factories.js";
5
- import { interpolateScriptExpressions, processExpressions, unescapeHtml } from "./expressions.js";
5
+ import { interpolateScriptExpressions, processExpressions } from "./expressions.js";
6
6
  import { COMPONENT_SCOPE_LOCAL_GLOBALS, buildRuntimeGlobalsDestructure } from "./runtime-globals.js";
7
7
  import { transformStoreImports } from "./store-imports.js";
8
8
  import { LRUCache } from "./performance-utils.js";
@@ -648,13 +648,6 @@ ${triedPaths.map((p) => ` - ${p}`).join(`
648
648
  templateContent = templateContent.replace(/\{\{\s*text\s*\|\|\s*slot\s*\}\}/g, () => slotContent);
649
649
  const { applySlots } = await importOnce("stx/slots", () => import("./slots.js")), { defaultSlot, namedSlots } = parsedSlotContent;
650
650
  templateContent = await applySlots(templateContent, defaultSlot, namedSlots, componentContext);
651
- for (const [key, value] of Object.entries(componentContext))
652
- if (typeof value === "string") {
653
- if (value.includes("<") && value.includes(">") || value.includes("&lt;") || value.includes("&quot;")) {
654
- const unescaped = unescapeHtml(value);
655
- componentContext[key] = unescaped;
656
- }
657
- }
658
651
  const hasSignalScripts = clientScripts.some((s) => /\b(?:state|derived|effect|ref|reactive|computed|watch|watchEffect|useReactiveProp|defineProps|withDefaults|defineEmits|defineExpose|defineSlots)\s*(?:<[^<>()]*>)?\s*\(/.test(s)), clientSignalNames = componentClientSignalNames(clientScripts);
659
652
  if (clientSignalNames.length > 0)
660
653
  componentContext.__stx_client_signal_names = clientSignalNames;
@@ -5,6 +5,14 @@
5
5
  * @returns JavaScript code with TypeScript syntax stripped
6
6
  */
7
7
  export declare function stripTypeScript(scriptContent: string): string;
8
+ /**
9
+ * Whether a script failure was a module that could not be found.
10
+ *
11
+ * Matched on the message because the failure arrives as a plain Error from the
12
+ * runtime's loader rather than a typed one, and the wording differs between
13
+ * Bun and Node.
14
+ */
15
+ export declare function isModuleResolutionFailure(message: string): boolean;
8
16
  export declare function extractVariables(scriptContent: string, context: Record<string, unknown>, filePath: string, options?: ExtractVariablesOptions): Promise<void>;
9
17
  /**
10
18
  * Convert ES module syntax to CommonJS
@@ -210,6 +210,9 @@ export function stripTypeScript(scriptContent) {
210
210
  `);
211
211
  return result;
212
212
  }
213
+ export function isModuleResolutionFailure(message) {
214
+ return /cannot find module|could not resolve|module not found|failed to resolve/i.test(message);
215
+ }
213
216
  export async function extractVariables(scriptContent, context, filePath, options = {}) {
214
217
  if (!scriptContent.trim())
215
218
  return;
@@ -470,10 +473,11 @@ export async function extractVariables(scriptContent, context, filePath, options
470
473
  if (!(key in context))
471
474
  context[key] = value;
472
475
  } catch (primaryError) {
473
- if (process.env.STX_DEBUG) {
474
- const msg = primaryError instanceof Error ? primaryError.message : String(primaryError);
476
+ const msg = primaryError instanceof Error ? primaryError.message : String(primaryError);
477
+ if (isModuleResolutionFailure(msg))
478
+ console.warn(`[stx] server <script> in ${filePath ?? "<unknown>"} imports a module that does not resolve, so every variable in that script is undefined. Cause: ${msg}`);
479
+ else if (process.env.STX_DEBUG)
475
480
  console.warn(`[stx] server <script> did not execute in ${filePath ?? "<unknown>"} \u2014 falling back to static extraction. Cause: ${msg}`);
476
- }
477
481
  try {
478
482
  await fallbackVariableExtraction(jsContent, context, filePath);
479
483
  } catch (fallbackError) {
@@ -590,13 +594,24 @@ export function convertToCommonJS(scriptContent, filePath) {
590
594
  convertedLines.push(`const ${name} = await import('${resolved}')`);
591
595
  convertedLines.push(`module.exports.${name} = ${name};`);
592
596
  } else if (namedImportMatch) {
593
- const [, names, source] = namedImportMatch, cleanNames = names.trim(), resolved = resolveSource(source);
594
- convertedLines.push(`const { ${cleanNames} } = await import('${resolved}')`);
595
- for (const n of cleanNames.split(",")) {
596
- const cleanName = n.trim().split(/\s+as\s+/).pop()?.trim();
597
- if (cleanName)
598
- convertedLines.push(`module.exports.${cleanName} = ${cleanName};`);
597
+ const [, names, source] = namedImportMatch, resolved = resolveSource(source), specifiers = [], exported = [];
598
+ for (const raw of names.split(",")) {
599
+ const specifier = raw.trim();
600
+ if (!specifier)
601
+ continue;
602
+ const aliased = specifier.split(/\s+as\s+/);
603
+ if (aliased.length === 2) {
604
+ const [imported, local] = [aliased[0].trim(), aliased[1].trim()];
605
+ specifiers.push(`${imported}: ${local}`);
606
+ exported.push(local);
607
+ } else {
608
+ specifiers.push(specifier);
609
+ exported.push(specifier);
610
+ }
599
611
  }
612
+ convertedLines.push(`const { ${specifiers.join(", ")} } = await import('${resolved}')`);
613
+ for (const local of exported)
614
+ convertedLines.push(`module.exports.${local} = ${local};`);
600
615
  } else if (sideEffectMatch) {
601
616
  const resolved = resolveSource(sideEffectMatch[1]);
602
617
  convertedLines.push(`await import('${resolved}')`);
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * Create a snapshot tester
3
3
  */
4
- export declare function createSnapshotTester(config?: VisualTestConfig): void;
4
+ export declare function createSnapshotTester(config?: VisualTestConfig): SnapshotTester;
5
5
  /**
6
6
  * Create a visual regression tester
7
7
  */
8
- export declare function createVisualRegressionTester(config?: VisualTestConfig): void;
8
+ export declare function createVisualRegressionTester(config?: VisualTestConfig): VisualRegressionTester;
9
9
  /**
10
10
  * Create a story-based visual tester
11
11
  */
12
- export declare function createStoryTester(config?: VisualTestConfig): void;
12
+ export declare function createStoryTester(config?: VisualTestConfig): StoryTester;
13
13
  /**
14
14
  * Generate visual test report
15
15
  */
@@ -89,6 +89,29 @@ export declare interface Story {
89
89
  args?: Record<string, unknown>
90
90
  viewports?: Viewport[]
91
91
  }
92
+ /** Handle returned by {@link createSnapshotTester}. */
93
+ export declare interface SnapshotTester {
94
+ snapshot: (html: string, name: string) => Promise<SnapshotResult>
95
+ snapshotJson: (data: unknown, name: string) => Promise<SnapshotResult>
96
+ matchInlineSnapshot: (actual: string, expected?: string) => { passed: boolean, expected: string }
97
+ getConfig: () => Required<VisualTestConfig>
98
+ }
99
+ /** Handle returned by {@link createVisualRegressionTester}. */
100
+ export declare interface VisualRegressionTester {
101
+ compareScreenshots: (name: string, actual: Buffer, viewport?: string) => Promise<ScreenshotResult>
102
+ testViewports: (name: string, captureScreenshot: (viewport: Viewport) => Promise<Buffer>, viewports?: Viewport[]) => Promise<ScreenshotResult[]>
103
+ getSnapshotTester: () => SnapshotTester
104
+ }
105
+ /** Handle returned by {@link createStoryTester}. */
106
+ export declare interface StoryTester {
107
+ addStory: (story: Story) => void
108
+ addStories: (storyList: Story[]) => void
109
+ getStories: () => Story[]
110
+ getStoriesForComponent: (component: string) => Story[]
111
+ testStory: (storyId: string) => Promise<VisualTestResult>
112
+ testAllStories: () => Promise<VisualTestResult[]>
113
+ generateStoryIndex: () => Promise<string>
114
+ }
92
115
  // =============================================================================
93
116
  // Test Reporter
94
117
  // =============================================================================
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/stx",
3
3
  "type": "module",
4
- "version": "0.2.150",
4
+ "version": "0.2.152",
5
5
  "description": "A performant UI Framework. Powered by Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",
@@ -117,12 +117,12 @@
117
117
  "dependencies": {
118
118
  "@cwcss/crosswind": "^0.2.14",
119
119
  "@stacksjs/clapp": "^0.2.0",
120
- "@stacksjs/desktop": "0.2.150",
121
- "@stacksjs/sanitizer": "0.2.150",
120
+ "@stacksjs/desktop": "0.2.152",
121
+ "@stacksjs/sanitizer": "0.2.152",
122
122
  "@stacksjs/ts-i18n": "^0.1.11",
123
- "bun-plugin-stx": "0.2.150",
123
+ "bun-plugin-stx": "0.2.152",
124
124
  "bunfig": "^0.15.17",
125
- "stx-router": "0.2.150",
125
+ "stx-router": "0.2.152",
126
126
  "ts-broadcasting": "^0.0.9",
127
127
  "ts-images": "^0.1.9",
128
128
  "ts-syntax-highlighter": "^0.2.1"