# ลิงก์แชร์ · Sharing links

เราอยากให้การส่งต่อสแต็กง่ายเหมือนส่งลิงก์บทความ ลิงก์แชร์จึงทำให้คุณส่ง "สแต็กที่ปรับแต่งแล้ว" ให้เพื่อนร่วมทีม หรือเก็บไว้สร้างซ้ำในอนาคตได้ โดยไม่ต้องมีบัญชีผู้ใช้ และเราก็ไม่ต้องเก็บข้อมูลของคุณไว้ในฐานข้อมูลใด ๆ

## รูปแบบลิงก์

| รูปแบบ | ตัวอย่าง | เปิดแล้วไปที่ |
|---|---|---|
| Share link | `/builder#s=eyJ2Ijox...` | ขั้น **Review & reorder** พร้อม config และการแก้ไขทั้งหมด และมี toast "Loaded a shared stack from the link." |
| Template link | `/builder#t=fastapi-ai` | ขั้น **Configure** ของเทมเพลตนั้นด้วยค่าเริ่มต้น (ปุ่ม Open in builder ใช้รูปแบบนี้) |
| Pick tab | `/builder#pick` | ขั้น Start โดยเปิดแท็บ Pick a template |

ถ้าไม่มี hash ตัวสร้างจะโหลดสถานะล่าสุดจาก `localStorage` (`nvx-builder-state`) หรือค่าเริ่มต้น (`nextjs-dashboard`)

## สิ่งที่อยู่ในลิงก์ และทำไมใช้ URL hash

token หลัง `#s=` คือ JSON ที่เข้ารหัสแบบ base64url มีฟิลด์: `v` (เวอร์ชันรูปแบบ = 1), `c` (config), `o` (ลำดับ id ที่ผู้ใช้จัด), `r` (id ที่ลบ), `x` (ขั้นตอนที่เพิ่มเอง) ส่วนที่ว่างจะไม่ถูกใส่เพื่อให้ลิงก์สั้น

เหตุผลที่เราเลือกใช้ **fragment (`#`)** แทน query string: เบราว์เซอร์ไม่ส่ง fragment ไปยังเซิร์ฟเวอร์ จึงไม่มีข้อมูลสแต็กไปโผล่ใน log ของเซิร์ฟเวอร์หรือ CDN และไม่ต้องมีฐานข้อมูลเก็บลิงก์ ข้อเสียคือลิงก์อาจยาวถ้ามีขั้นตอนเพิ่มเองเยอะ (จำกัด token ไม่เกิน 60,000 ตัวอักษร)

## ความปลอดภัยของลิงก์ที่ได้รับ

ลิงก์แชร์ถือเป็น **ข้อมูลไม่น่าเชื่อถือ (untrusted)** เพราะใครก็สร้างได้ ตอนเปิด `decodeShare` จะ:

- ตรวจรูปแบบด้วย zod schema (จำกัดจำนวน: order/removed ≤ 100 รายการ, custom ≤ 20 ขั้น)
- ทำ config ให้ถูกต้องด้วย `normalizeConfig` (ค่าที่ไม่รู้จักกลับเป็นค่าเริ่มต้น, ชื่อโปรเจกต์ถูก sanitize)
- ส่งทุกขั้นตอนที่เพิ่มเองผ่าน `sanitizeStep` คำสั่งทำลายระบบถูกตัดทิ้ง คำสั่งเสี่ยงกลายเป็น manual (คอมเมนต์ไว้ในสคริปต์)
- token เสียหรือไม่ถูกต้อง → คืน `null` และตัวสร้างใช้ค่าเริ่มต้นแทน ไม่ crash

ถึงเราจะป้องกันไว้หลายชั้น ก็ขอฝากให้ **อ่านสคริปต์ก่อนรันทุกครั้ง** โดยเฉพาะลิงก์จากคนที่คุณไม่รู้จัก

## วิธีแชร์

1. ไปขั้น Export แล้วกด **Copy share link** (หรือคัดลอก URL จากแถบที่อยู่ ซึ่งอัปเดตตลอด)
2. ส่งลิงก์ ผู้รับเปิดแล้วจะได้สแต็กเดียวกันทุกประการ
3. ไฟล์ `README.md` และ `nvx-stack.json` ในไฟล์ zip ก็มีลิงก์นี้ด้วย

## ความเข้ากันได้ข้ามเวอร์ชัน

เราสัญญากับตัวเองว่าลิงก์เก่าต้องเปิดได้เสมอ รูปแบบ `v: 1` จึงไม่เปลี่ยนเลยตั้งแต่ v0.1.0 (commit `a452dc5`) ถ้า id ของขั้นตอนในเทมเพลตเปลี่ยนภายหลัง ลำดับที่อ้าง id เก่าจะถูกข้าม และขั้นใหม่ถูกแทรกต่อจากขั้นก่อนหน้าตามธรรมชาติ (`applyEdits`) ถ้าวันหนึ่งต้องเปลี่ยนรูปแบบ เราจะเพิ่ม `v: 2` และคงตัวถอดรหัส `v: 1` ไว้

## อ้างอิง

[`src/lib/share.ts`](../../src/lib/share.ts), [`src/lib/sanitize.ts`](../../src/lib/sanitize.ts), [`src/components/builder.tsx`](../../src/components/builder.tsx), สถาปัตยกรรม: [scripts-and-share.md](../architecture/scripts-and-share.md)
