')
- expect(result.html).toContain("GET:/demo")
- expect(result.html).toContain('id="__loom_payload__"')
- expect(result.html).toContain(``)
- })
-
- it("surfaces canonical resumability diagnostics through the Nitro adapter result", async () => {
- const result = await renderLoomNitroResponse(
- {
- rootId: "loom-root",
- render: () =>
- Html.el(
- "section",
- Html.hydrate(Hydration.visible()),
- Html.on("click", { _tag: "EffectLike" }),
- Html.children("ready"),
- ),
- },
- {
- method: "GET",
- url: "/unsupported",
- headers: {},
- },
- )
-
- expect(result.resumability).toBeUndefined()
- expect(result.diagnosticSummary).toEqual([
- {
- phase: "resumability",
- total: 1,
- highestSeverity: "error",
- hasErrors: true,
- },
- ])
- })
-
- it("exposes the initial Nitro adapter module shape", async () => {
- const nitro = renderer({
- render: (request) => Html.el("main", Html.children(request.url)),
- })
-
- expect(nitro.name).toBe("effectify:loom-nitro")
- await expect(
- nitro.render({
- method: "GET",
- url: "/static",
- headers: {},
- }),
- ).resolves.toMatchObject({
- html: expect.stringContaining("
/static"),
- resumability: undefined,
- })
- })
-
- it("uses an explicit custom document override while keeping bootstrap metadata configurable", async () => {
- const result = await renderLoomNitroResponse(
- {
- bootstrap: {
- rootId: "custom-root",
- payloadElementId: "custom-payload",
- clientEntry: "/src/custom-entry.ts",
- },
- document: {
- render: ({ bodyHtml, payloadHtml, bootstrap, title }) =>
- `
${title}${bodyHtml}
${payloadHtml}`,
- },
- render: () => ({
- title: "Custom shell",
- body: Html.el("section", Html.hydrate(Hydration.visible()), Html.children("body")),
- }),
- },
- {
- method: "GET",
- url: "/custom",
- headers: {},
- },
- )
-
- expect(result.html).toContain("custom-shell")
- expect(result.html).toContain('id="custom-root"')
- expect(result.html).toContain('id="custom-payload"')
- expect(result.html).toContain('data-client-entry="/src/custom-entry.ts"')
- expect(result.resumability?.rootId).toBe("custom-root")
- })
-})
diff --git a/packages/loom/nitro/tests/public-api.types.ts b/packages/loom/nitro/tests/public-api.types.ts
deleted file mode 100644
index 226e84e5..00000000
--- a/packages/loom/nitro/tests/public-api.types.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Diagnostics, Html } from "@effectify/loom"
-import { LoomNitro } from "../src/index.js"
-
-type Equal
= (() => Value extends Left ? 1 : 2) extends () => Value extends Right ? 1 : 2
- ? true
- : false
-type Expect = Value
-
-const descriptor = LoomNitro.renderer({
- render: (request) => ({
- title: request.url,
- body: Html.el("main", Html.children(request.url)),
- }),
-})
-
-LoomNitro.renderer({
- bootstrap: {
- clientEntry: "/src/entry-client.ts",
- payloadElementId: "loom-payload",
- rootId: "loom-root",
- },
- render: (request) => Html.el("main", Html.children(request.url)),
- // @ts-expect-error non-web renderers remain out of scope for this web-only adapter
- renderer: "native",
-})
-
-type RenderResult = Awaited>
-type ResultContract = Expect>
-type DiagnosticSummaryContract = Expect>>
-
-export const typecheckSmoke = {
- descriptor,
-}
-
-export type { DiagnosticSummaryContract, ResultContract }
diff --git a/packages/loom/nitro/tests/resumability-payload.test.ts b/packages/loom/nitro/tests/resumability-payload.test.ts
deleted file mode 100644
index 2600b39a..00000000
--- a/packages/loom/nitro/tests/resumability-payload.test.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { describe, expect, it } from "vitest"
-import { Html, Hydration, Resumability } from "../../web/src/index.js"
-import {
- createLoomResumabilityPayload,
- decodeLoomResumabilityPayload,
- encodeLoomResumabilityPayload,
- renderLoomPayloadElement,
-} from "../src/internal/payload.js"
-import { renderLoomNitroResponse } from "../src/internal/ssr-adapter.js"
-
-const effectLike = { _tag: "EffectLike" } as const
-
-describe("@effectify/loom-nitro resumability payload", () => {
- it("creates a serialized resumability payload from SSR output and round-trips it", async () => {
- const clickRef = Resumability.makeExecutableRef("app/counter", "onClick")
-
- const render = Html.ssr(
- Html.el(
- "section",
- Html.hydrate(Hydration.visible()),
- Html.on("click", Resumability.handler(clickRef, effectLike)),
- Html.children("ready"),
- ),
- )
-
- const payload = await createLoomResumabilityPayload({
- buildId: "build-123",
- rootId: "loom-root",
- }, render)
-
- expect(payload).toBeDefined()
-
- if (payload === undefined) {
- throw new Error("expected resumability payload")
- }
-
- expect(payload).toMatchObject({
- version: 1,
- buildId: "build-123",
- rootId: "loom-root",
- handlers: [
- expect.objectContaining({
- ref: clickRef,
- event: "click",
- }),
- ],
- liveRegions: [],
- })
-
- await expect(decodeLoomResumabilityPayload(encodeLoomResumabilityPayload(payload), {
- expectedBuildId: "build-123",
- })).resolves.toEqual({
- status: "valid",
- contract: payload,
- issues: [],
- })
-
- expect(renderLoomPayloadElement(payload, "loom-payload")).toContain('id="loom-payload"')
- })
-
- it("keeps unsupported resumability cases honest by skipping payload creation", async () => {
- const render = Html.ssr(
- Html.el(
- "section",
- Html.hydrate(Hydration.visible()),
- Html.on("click", effectLike),
- Html.children("ready"),
- ),
- )
-
- await expect(createLoomResumabilityPayload({
- buildId: "build-123",
- rootId: "loom-root",
- }, render)).resolves.toBeUndefined()
- })
-
- it("keeps the default shell and bootstrap markers when the route body is missing", async () => {
- const result = await renderLoomNitroResponse(
- {
- render: () => ({
- title: "Broken route",
- body: undefined,
- }),
- },
- {
- method: "GET",
- url: "/broken",
- headers: {},
- },
- )
-
- expect(result.html).toContain("Broken route")
- expect(result.html).toContain('')
- expect(result.html).toContain('id="__loom_payload__"')
- expect(result.html).toContain('src="/src/entry-client.ts"')
- })
-})
diff --git a/packages/loom/nitro/tsconfig.json b/packages/loom/nitro/tsconfig.json
deleted file mode 100644
index bef76912..00000000
--- a/packages/loom/nitro/tsconfig.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "extends": "../../../tsconfig.base.json",
- "compilerOptions": {},
- "files": [],
- "include": [],
- "references": [
- {
- "path": "./tsconfig.lib.json"
- },
- {
- "path": "./tsconfig.spec.json"
- }
- ]
-}
diff --git a/packages/loom/nitro/tsconfig.lib.json b/packages/loom/nitro/tsconfig.lib.json
deleted file mode 100644
index 7bbd6941..00000000
--- a/packages/loom/nitro/tsconfig.lib.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "compilerOptions": {
- "rootDir": "..",
- "outDir": "../../../dist/out-tsc",
- "declaration": true,
- "types": ["node"],
- "target": "ES2022",
- "lib": ["ES2022", "DOM", "DOM.Iterable"]
- },
- "include": ["src/**/*.ts"]
-}
diff --git a/packages/loom/nitro/tsconfig.spec.json b/packages/loom/nitro/tsconfig.spec.json
deleted file mode 100644
index 02bcba4b..00000000
--- a/packages/loom/nitro/tsconfig.spec.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "extends": "./tsconfig.json",
- "compilerOptions": {
- "rootDir": "..",
- "outDir": "../../../dist/out-tsc",
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
- "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
- },
- "include": [
- "vite.config.ts",
- "vite.config.mts",
- "vitest.config.ts",
- "vitest.config.mts",
- "tests/**/*.ts",
- "src/**/*.test.ts",
- "src/**/*.spec.ts",
- "src/**/*.test.tsx",
- "src/**/*.spec.tsx",
- "src/**/*.d.ts"
- ]
-}
diff --git a/packages/loom/nitro/vitest.config.mts b/packages/loom/nitro/vitest.config.mts
deleted file mode 100644
index 68186ea4..00000000
--- a/packages/loom/nitro/vitest.config.mts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { nxCopyAssetsPlugin } from "@nx/vite/plugins/nx-copy-assets.plugin"
-import { nxViteTsPaths } from "@nx/vite/plugins/nx-tsconfig-paths.plugin"
-import { defineConfig } from "vitest/config"
-
-export default defineConfig(() => ({
- root: __dirname,
- cacheDir: "../../../node_modules/.vite/packages/loom/nitro",
- plugins: [nxViteTsPaths(), nxCopyAssetsPlugin(["*.md"])],
- test: {
- name: "@effectify/loom-nitro",
- watch: false,
- globals: true,
- environment: "node",
- include: ["{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
- reporters: ["default"],
- coverage: {
- reportsDirectory: "../../../coverage/packages/loom/nitro",
- provider: "v8" as const,
- },
- },
-}))
diff --git a/packages/loom/router/package.json b/packages/loom/router/package.json
deleted file mode 100644
index 95879933..00000000
--- a/packages/loom/router/package.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "name": "@effectify/loom-router",
- "version": "0.0.1",
- "description": "Routing surface for Loom",
- "repository": {
- "type": "git",
- "url": "https://github.com/devx-op/effectify",
- "directory": "packages/loom/router"
- },
- "type": "module",
- "publishConfig": {
- "access": "public"
- },
- "main": "./src/index.ts",
- "types": "./src/index.ts",
- "exports": {
- ".": {
- "@effectify/source": "./src/index.ts",
- "types": "./src/index.ts",
- "import": "./src/index.ts",
- "default": "./src/index.ts"
- },
- "./Decode": "./src/decode.ts",
- "./Fallback": "./src/fallback.ts",
- "./Layout": "./src/layout.ts",
- "./Link": "./src/link.ts",
- "./Match": "./src/match.ts",
- "./Navigation": "./src/navigation.ts",
- "./Route": "./src/route.ts",
- "./RouteModule": "./src/route-module.ts",
- "./RouteGroup": "./src/route-group.ts",
- "./Router": "./src/router.ts",
- "./Runtime": "./src/router-runtime.ts",
- "./Submission": "./src/submission.ts"
- },
- "dependencies": {
- "effect": "catalog:",
- "tslib": "catalog:"
- },
- "peerDependencies": {
- "@effectify/loom": "workspace:*",
- "effect": "^4.0.0-beta"
- }
-}
diff --git a/packages/loom/router/project.json b/packages/loom/router/project.json
deleted file mode 100644
index 27608c7b..00000000
--- a/packages/loom/router/project.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "name": "@effectify/loom-router",
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
- "sourceRoot": "packages/loom/router/src",
- "projectType": "library",
- "tags": ["loom", "public", "router"],
- "targets": {
- "typecheck": {
- "executor": "nx:run-commands",
- "options": {
- "command": "tsc --noEmit -p tsconfig.lib.json && tsc --noEmit -p tsconfig.spec.json",
- "cwd": "packages/loom/router"
- }
- },
- "test": {
- "executor": "nx:run-commands",
- "options": {
- "command": "../../../node_modules/.bin/vitest run --config vitest.config.mts",
- "cwd": "packages/loom/router"
- }
- },
- "lint": {
- "executor": "nx-oxlint:lint",
- "outputs": ["{options.outputFile}"],
- "options": {
- "lintFilePatterns": ["packages/loom/router/**/*.{ts,tsx,js,jsx,mts,cts}"]
- }
- }
- }
-}
diff --git a/packages/loom/router/src/action-input.ts b/packages/loom/router/src/action-input.ts
deleted file mode 100644
index b442d374..00000000
--- a/packages/loom/router/src/action-input.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-import * as Result from "effect/Result"
-import * as Schema from "effect/Schema"
-
-export type Value = string | ReadonlyArray
-
-export type Normalized = Readonly>
-
-type RecordValue = string | number | boolean | null | undefined
-type SubmissionRecord = Readonly>>
-
-export type Submission =
- | FormData
- | URLSearchParams
- | SubmissionRecord
- | Normalized
-
-export interface Failure {
- readonly _tag: "LoomRouterActionInputFailure"
- readonly message: string
- readonly input: unknown
-}
-
-export interface Decoder