Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
67b4309
test(seo): add safe JSON-LD renderer
baixiangcpp Jun 17, 2026
aaf4cdd
feat(routing): make tool handoff sessionStorage-first
baixiangcpp Jun 17, 2026
282b898
test(security): require network access metadata
baixiangcpp Jun 17, 2026
ac55cb4
feat(storage): add input persistence policy
baixiangcpp Jun 17, 2026
ad5b189
chore(seo): refresh sitemap lastmod manifest
baixiangcpp Jun 17, 2026
4a92ae7
feat(storage): mark sensitive tools non-persistent
baixiangcpp Jun 17, 2026
f9e784c
feat(security): show external network notices
baixiangcpp Jun 17, 2026
60ae25f
test(security): guard html injection surfaces
baixiangcpp Jun 17, 2026
2b559fd
refactor(json-formatter): extract page UI modules
baixiangcpp Jun 17, 2026
a52c450
test(json-formatter): cover tree path mutations
baixiangcpp Jun 17, 2026
a9a1ba2
refactor(pipeline-builder): extract page panels
baixiangcpp Jun 17, 2026
4bed3a6
test(pipeline): cover validation and execution edges
baixiangcpp Jun 17, 2026
ad8eeb8
feat(registry): generate manifest aggregator
baixiangcpp Jun 17, 2026
d63e099
test(architecture): guard tool page side effects
baixiangcpp Jun 17, 2026
ff9720a
feat(pipeline): require adapter criteria metadata
baixiangcpp Jun 17, 2026
f98f6af
feat(pipeline): add phase one data adapters
baixiangcpp Jun 17, 2026
e75e6d1
feat(pipeline): add text utility adapters
baixiangcpp Jun 17, 2026
6861d31
feat(pipeline): add regex and env adapters
baixiangcpp Jun 17, 2026
692f61e
feat(pipeline): harden recipe sharing UX
baixiangcpp Jun 17, 2026
512f85d
feat(discovery): add tool taxonomy filters
baixiangcpp Jun 17, 2026
93a85f8
test(security): document inline script CSP policy
baixiangcpp Jun 17, 2026
d4b253d
feat(security): harden external URL handling
baixiangcpp Jun 17, 2026
ce073ea
test(perf): add runtime and bundle guardrails
baixiangcpp Jun 17, 2026
2da6cef
test(qa): expand smoke and parser coverage
baixiangcpp Jun 17, 2026
99c8642
chore(scaffold): improve tool creation workflow
baixiangcpp Jun 17, 2026
c351a3e
chore(seo): refresh sitemap lastmod manifest
baixiangcpp Jun 17, 2026
8f1f072
test(e2e): harden pwa smoke coverage
baixiangcpp Jun 17, 2026
7b825ee
test(qa): close roadmap audit gaps
baixiangcpp Jun 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,23 +131,35 @@ Manifests:
- Tool manifests must export `toolManifest = { ... } satisfies ToolMeta`.
- Keep manifest fields literal and statically parseable.
- Do not use spreads, computed keys, functions, template literals, dynamic imports, React imports, or client-only imports in manifests.
- Set `networkAccess` when a tool opens external pages, fetches user-provided URLs, or relies on third-party APIs.
- Set `persistInput` deliberately. Sensitive payload tools should use `false`; tools that save payloads should explain that behavior in UI copy.
- Discovery `family`, `tags`, and `capabilities` are generated from manifest metadata and taxonomy rules. Do not hand-edit generated taxonomy fields.

## Adding a Tool

Use the scaffolder when possible:

```bash
npm run create:tool
npm run create:tool -- --slug my-new-tool --category formatters
```

Useful scaffolder flags:

- `--network-access none|user_requested|third_party_api`
- `--persist-input true|false|opt-in`
- `--pipeline-adapter` to mark that the tool needs a matching adapter design before it should appear as pipeline-ready
- `--search-keywords term1,term2` for additional command palette and discovery matching

The expected shape is:

- `src/features/tools/{slug}/manifest.ts`
- `src/features/tools/{slug}/page.tsx`
- `src/features/tools/{slug}/logic.ts` and `logic.test.ts`
- `src/app/[lang]/{slug}/page.tsx`
- Optional feature-local `logic.ts`, `types.ts`, `samples.ts`, `constants.ts`, `browser-actions.ts`, `hooks.ts`, or `components.tsx`
- Translation entries in every supported locale
- Tests for pure logic and any important UI or routing behavior
- Runtime budgets, external URL validation, and accessibility coverage when the tool parses large payloads, fetches URLs, renders previews, or uses icon-only controls

After changing tool manifests, run:

Expand Down
19 changes: 18 additions & 1 deletion docs/specs/pipeline-recipe-builder-technical-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ export interface PipelineToolAdapter<Input = string, Output = string> {
version: number
inputKind: "text" | "json" | "yaml" | "csv" | "bytes"
outputKind: "text" | "json" | "yaml" | "csv" | "bytes"
safeForSensitiveInput: boolean
deterministic: boolean
mayIncreaseSize: boolean
warnings: readonly string[]
defaultOptions: Record<string, unknown>
publicOptionKeys: readonly string[]
validateOptions(options: Record<string, unknown>): AdapterValidationResult
Expand Down Expand Up @@ -163,6 +167,10 @@ Adapter rules:
- Adapters must not import page components.
- Adapters must not call `fetch` except for same-page static assets already used by an existing local tool.
- Adapters must not persist payloads.
- Adapters must be deterministic for the same input and options. Non-deterministic generators, canvas/image editing flows, and external-network tools need a separate design before inclusion.
- `safeForSensitiveInput` means the adapter is appropriate for local sensitive payloads; it does not imply output is safe to share unless the adapter redacts or removes sensitive content.
- `mayIncreaseSize` must be true for reversible encoders and pretty-printers that can expand payloads.
- `warnings` must describe persistent adapter-level caveats shown or available to UI surfaces.
- Adapters must return structured warnings instead of throwing for expected user errors.
- Adapters must have unit tests covering success and failure paths.
- `publicOptionKeys` controls which options are allowed into shared recipe URLs.
Expand All @@ -181,6 +189,16 @@ The current non-public foundation includes only deterministic, low-risk text/dat
| `multiple_whitespace_remover` | Simple text normalization. |
| `invisible_chars_detector` | Clean copied config/log text before parsing. |
| `log_scrubber` | Redact sensitive log content before export. |
| `yaml_json_converter` | Convert YAML snippets to JSON and JSON snippets back to YAML in local data workflows. |
| `csv_json_converter` | Bridge tabular CSV data into JSON and convert JSON arrays back to CSV. |
| `ndjson_formatter` | Convert JSON arrays and newline-delimited JSON records for log/data pipelines. |
| `slugify_case_converter` | Normalize strings into deterministic slug and case formats. |
| `hash_generator` | Produce deterministic text digests for checksum and fixture workflows. |
| `jwt_decoder` | Decode JWT header and payload JSON without signature verification. |
| `unix_timestamp` | Convert Unix seconds or milliseconds into ISO or structured JSON output. |
| `html_to_markdown` | Convert HTML snippets into Markdown text for content cleanup pipelines. |
| `regex_tester` | Produce JSON match summaries for deterministic pattern checks. |
| `env_parser` | Parse `.env` content into JSON, YAML, or docker argument text. |

### Phase 3D Target Expansion / Public MVP Candidates

Expand All @@ -190,7 +208,6 @@ These remain future candidates and are not part of the current foundation adapte
|----------|--------|
| `jq_playground` | Existing local JSON transform runtime. |
| `yq_playground` | Local yq-like YAML/JSON subset. |
| `yaml_json_converter` | Common bridge between YAML and JSON. |
| `local_log_parser` | Parse logs before filtering/export. |
| Other deterministic adapters | Add only after each adapter has explicit validation and public option keys. |

Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"scripts": {
"dev": "next dev",
"analyze": "ANALYZE=true next build --webpack",
"validate": "npm run check:sw-version && npm run check:sitemap-lastmod && npm run check:security-headers && npm run check:pwa-manifests && npm run check:og-tool-images && npm run check:ia-stability && npm run check:analytics-taxonomy && npm run check:tool-index && npm run check:client-tool-lookup && npm run check:i18n && npm run check:types",
"validate": "npm run check:sw-version && npm run check:sitemap-lastmod && npm run check:security-headers && npm run check:pwa-manifests && npm run check:bundle-boundaries && npm run check:og-tool-images && npm run check:ia-stability && npm run check:analytics-taxonomy && npm run check:registry-manifests && npm run check:tool-index && npm run check:client-tool-lookup && npm run check:i18n && npm run check:types",
"build:app": "next build",
"build:post": "npm run check:canonical && npm run check:hreflang && npm run check:metadata-localization && npm run check:rendered-i18n-copy && npm run check:related-tools && npm run check:content-template:legacy-paths && npm run check:content-template && npm run check:content-template:quality && npm run check:faq-schema && npm run check:content-template:zh-cn && npm run check:content-template:quality:zh-cn && npm run check:faq-schema:zh-cn && npm run check:content-template:zh-tw && npm run check:content-template:quality:zh-tw && npm run check:faq-schema:zh-tw && npm run check:content-template:ja && npm run check:content-template:quality:ja && npm run check:faq-schema:ja && npm run check:content-template:ko && npm run check:content-template:quality:ko && npm run check:faq-schema:ko && npm run check:content-template:de && npm run check:content-template:quality:de && npm run check:faq-schema:de && npm run check:content-template:fr && npm run check:content-template:quality:fr && npm run check:faq-schema:fr && npm run postprocess:export-html-lang && npm run check:export-html-lang && npm run postprocess:export-robots-meta && npm run check:export-robots-meta && npm run build:sw",
"build": "npm run validate && npm run build:app && npm run build:post",
Expand All @@ -72,9 +72,12 @@
"check:ia-stability": "node scripts/gates/check-ia-stability.js",
"check:analytics-taxonomy": "node scripts/gates/check-analytics-taxonomy.js",
"check:security-headers": "node scripts/gates/check-security-headers-config.js",
"check:bundle-boundaries": "node scripts/gates/check-bundle-boundaries.js",
"check:sw-version": "node scripts/gates/check-sw-version-bump.js",
"build:sw": "node scripts/postprocess/inject-sw-build-id.js",
"check:types": "tsc --noEmit",
"generate:registry-manifests": "node scripts/generators/generate-registry-manifests.js",
"check:registry-manifests": "node scripts/generators/generate-registry-manifests.js --check",
"generate:tool-index": "node scripts/generators/generate-tool-index.js",
"check:tool-index": "node scripts/generators/generate-tool-index.js --check",
"generate:client-tool-lookup": "node scripts/generators/generate-client-tool-lookup.js",
Expand Down
24 changes: 18 additions & 6 deletions public/sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
const APP_VERSION = '__BUILD_ID__';
const CACHE_NAME = `byteflow-v${APP_VERSION}`;
const OFFLINE_FALLBACK_URL = '/offline.html';
const OFFLINE_FALLBACK_CANDIDATES = [OFFLINE_FALLBACK_URL, '/offline'];

const STATIC_ASSETS = [
'/manifest.json',
Expand All @@ -24,9 +25,18 @@ const STATIC_ASSETS = [
'/icon-maskable-512.png',
'/icon.png',
'/apple-icon.png',
OFFLINE_FALLBACK_URL,
...OFFLINE_FALLBACK_CANDIDATES,
];

function matchOfflineFallback() {
return caches.match(OFFLINE_FALLBACK_URL)
.then((cached) => cached || caches.match('/offline'))
.then((cached) => cached || new Response(
'<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Offline | byteflow.tools</title></head><body><main><h1>You are offline</h1><p>Reconnect and refresh, or open a page you have visited before.</p></main></body></html>',
{ headers: { 'Content-Type': 'text/html; charset=utf-8' } },
));
}

// Install: cache critical static assets; waiting/activation is user-triggered from the app shell.
self.addEventListener('install', (event) => {
event.waitUntil(
Expand Down Expand Up @@ -86,7 +96,7 @@ self.addEventListener('fetch', (event) => {
return response;
})
.catch(() =>
caches.match(event.request).then((cached) => cached || caches.match(OFFLINE_FALLBACK_URL))
caches.match(event.request).then((cached) => cached || matchOfflineFallback())
)
);
return;
Expand Down Expand Up @@ -118,7 +128,9 @@ self.addEventListener('fetch', (event) => {
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
}
return response;
})
.catch(() => caches.match(event.request))
);
});
})
.catch(() =>
caches.match(event.request).then((cached) => cached || matchOfflineFallback())
)
);
});
Loading
Loading