[{"data":1,"prerenderedAt":2573},["ShallowReactive",2],{"posts":3,"\u002Ffullstack\u002Fbrowser-to-server-save-form":205},[4,21,32,42,52,61,69,77,86,94,102,110,119,127,135,148,162,173,183,194],{"path":5,"title":6,"description":7,"type":8,"level":9,"minutes":10,"date":11,"cover":12,"coverAlt":13,"featured":14,"tags":15,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-cloudflare-tunnel","גישה ל-Home Assistant מחוץ לבית עם Cloudflare Tunnel","מחברים את Home Assistant לכתובת משלכם בלי לפתוח פורט בנתב. מדריך ל-Home Assistant OS ול-Docker, עם הרשאות גישה ובדיקות מהטלפון.","מדריך","רמת ביניים",14,"2026-10-04","\u002Fimages\u002Fposts\u002Fhome-assistant-cloudflare-tunnel.svg","טלפון מחוץ לבית מתחבר דרך Cloudflare Tunnel ומחבר מקומי ל-Home Assistant בבית.",false,[16,17,18,19],"Home Assistant","Cloudflare","Docker","בית חכם","smart-home",{"path":22,"title":23,"description":24,"type":8,"level":25,"minutes":26,"date":27,"cover":28,"coverAlt":29,"featured":14,"tags":30,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-backup-update-recovery","גיבוי שאפשר לשחזר, ועדכון שאפשר להתאושש ממנו","מגדירים עותק גיבוי מחוץ לשרת, שומרים מפתח הצפנה ובודקים שחזור מבודד לפני שמעדכנים את הבית הפעיל.","למתחילים",8,"2026-09-29","\u002Fimages\u002Fposts\u002Fhome-assistant-backup-update-recovery.svg","שרת מקומי, ארכיון גיבוי ועותק חיצוני מחוברים למסלול שחזור.",[16,18,31],"גיבוי",{"path":33,"title":34,"description":35,"type":8,"level":25,"minutes":26,"date":36,"cover":37,"coverAlt":38,"featured":14,"tags":39,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-device-maintenance","חיישן נעלם? תחזוקה של מכשירים וסוללות","בונים רשימת תחזוקה קצרה, מפרידים בין סוללה חלשה למכשיר לא זמין ומאתרים בעיות דיווח בלי לאפס את הרשת.","2026-09-24","\u002Fimages\u002Fposts\u002Fhome-assistant-device-maintenance.svg","סוללה חלשה, רשת מכשירים עם צומת לא זמין וכלי תחזוקה.",[16,40,41],"חיישנים","Zigbee",{"path":43,"title":44,"description":45,"type":8,"level":25,"minutes":26,"date":46,"cover":47,"coverAlt":48,"featured":14,"tags":49,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-washing-machine-finished","מכונת הכביסה סיימה: התראה לפי צריכת חשמל","מודדים מחזור כביסה, מגדירים ספי הספק מתוך הנתונים ושולחים התראה רק אחרי ריצה שזוהתה, עם טיפול בדיווח חסר.","2026-09-19","\u002Fimages\u002Fposts\u002Fhome-assistant-washing-machine-finished.svg","מכונת כביסה מחוברת לגרף צריכת הספק ולהודעת סיום בטלפון.",[16,50,51,40],"אוטומציות","YAML",{"path":53,"title":54,"description":55,"type":8,"level":25,"minutes":56,"date":57,"cover":58,"coverAlt":59,"featured":14,"tags":60,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-smart-button-actions","כפתור חכם במקום עוד אפליקציה","מחברים כפתור פיזי לפעולה יומיומית, מזהים איך האינטגרציה מדווחת על לחיצות ובודקים תגובה בלי להסתמך על דגם מסוים.",7,"2026-09-14","\u002Fimages\u002Fposts\u002Fhome-assistant-smart-button-actions.svg","יד לוחצת על כפתור פיזי שמפעיל תאורה ותריס במסגרת סצנה.",[16,50,41],{"path":62,"title":63,"description":64,"type":8,"level":25,"minutes":56,"date":65,"cover":66,"coverAlt":67,"featured":14,"tags":68,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-helpers-house-modes","Helpers: נותנים לבית מצבים וזיכרון","מוסיפים מצב אורחים שנשלט מלוח הבקרה, מחברים אותו לתנאי באוטומציה ובודקים מה קורה אחרי אתחול.","2026-09-09","\u002Fimages\u002Fposts\u002Fhome-assistant-helpers-house-modes.svg","בורר מצבי בית מחובר למתגי עזר שמייצגים אורחים, יציאה והשהיה.",[16,50,51],{"path":70,"title":71,"description":72,"type":8,"level":25,"minutes":56,"date":73,"cover":74,"coverAlt":75,"featured":14,"tags":76,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-automation-debugging","האוטומציה לא עבדה: מוצאים את הסיבה","בודקים טריגרים, תנאים ופעולות לפי הסדר, קוראים Trace ומבחינים בין תקלה בחיישן לבין כלל שלא התקיים.","2026-09-04","\u002Fimages\u002Fposts\u002Fhome-assistant-automation-debugging.svg","מסלול אוטומציה מתפצל לתנאי ולפעולה, וזכוכית מגדלת מדגישה את נקודת הבדיקה.",[16,50,51],{"path":78,"title":79,"description":80,"type":8,"level":25,"minutes":56,"date":81,"cover":82,"coverAlt":83,"featured":14,"tags":84,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-light-manual-control","האור נכבה כשאתם עדיין בחדר? שיפור אוטומציית התאורה","משפרים תאורה לפי תנועה בעזרת כיבוי נפרד ומתג להשארת אור, ובודקים מה קורה בזמן קריאה, בהפעלה מחדש ובשחרור השליטה הידנית.","2026-08-30","\u002Fimages\u002Fposts\u002Fhome-assistant-light-manual-control.svg","חיישן תנועה, אדם בחדר ומנורה מופיעים לצד מתג שמאפשר להשהות כיבוי אוטומטי.",[16,19,50,85],"תאורה",{"path":87,"title":88,"description":89,"type":8,"level":25,"minutes":26,"date":90,"cover":91,"coverAlt":92,"featured":14,"tags":93,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-presence-detection","מי בבית? זיהוי נוכחות בלי כיבויים מפתיעים","מחברים את הטלפון לישות Person, בודקים זיהוי כניסה ויציאה ובונים התראת עזיבה שממתינה ולא מתייחסת למידע חסר כאל בית ריק.","2026-08-25","\u002Fimages\u002Fposts\u002Fhome-assistant-presence-detection.svg","שני אנשים מחוץ לבית, אזור נוכחות סביב הבית ושעון להשהיית פעולות יציאה.",[16,19,50],{"path":95,"title":96,"description":97,"type":8,"level":25,"minutes":56,"date":98,"cover":99,"coverAlt":100,"featured":14,"tags":101,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-useful-notifications","התראות שימושיות בלי להציף את הטלפון","מגדירים התראה כשהדלת נשארת פתוחה, בודקים הודעת ניסיון ומונעים הודעות חוזרות על כל פתיחה קצרה.","2026-08-20","\u002Fimages\u002Fposts\u002Fhome-assistant-useful-notifications.svg","דלת פתוחה מחוברת לשעון המתנה ולהתראה אחת בטלפון.",[16,19,50],{"path":103,"title":104,"description":105,"type":8,"level":25,"minutes":56,"date":106,"cover":107,"coverAlt":108,"featured":14,"tags":109,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-scenes-scripts","לילה טוב בלחיצה אחת: סצנות וסקריפטים","יוצרים סצנת ערב וסקריפט ״לילה טוב״ ב-Home Assistant, ומבינים מתי לשמור מצבים ומתי להריץ רצף פעולות.","2026-08-15","\u002Fimages\u002Fposts\u002Fhome-assistant-scenes-scripts.svg","כפתור אחד מפעיל רצף פעולות שמוביל לבית במצב לילה.",[16,19,50],{"path":111,"title":112,"description":113,"type":8,"level":25,"minutes":56,"date":114,"cover":115,"coverAlt":116,"featured":14,"tags":117,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-family-dashboard","לוח בקרה שבני הבית באמת ישתמשו בו","בונים לוח בקרה מובנה ב-Home Assistant עם חדרים, כפתורים ברורים ותצוגה נוחה בטלפון, בלי להתקין הרחבות.","2026-08-10","\u002Fimages\u002Fposts\u002Fhome-assistant-family-dashboard.svg","לוח בקרה גדול עם כפתורי תאורה וטמפרטורה מופיע לצד גרסה מותאמת לטלפון.",[16,19,118],"Dashboard",{"path":120,"title":121,"description":122,"type":8,"level":25,"minutes":56,"date":123,"cover":124,"coverAlt":125,"featured":14,"tags":126,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-organize-devices","עושים סדר בבית: חדרים, מכשירים וישויות","מסדרים את Home Assistant לפי חדרים, מבינים מה ההבדל בין מכשיר לישות ובוחרים שמות שקל למצוא בלי לשבור אוטומציות.","2026-08-05","\u002Fimages\u002Fposts\u002Fhome-assistant-organize-devices.svg","תוכנית חדרים מחוברת למכשיר אחד ולשלוש ישויות נפרדות.",[16,19,50],{"path":128,"title":129,"description":130,"type":8,"level":25,"minutes":26,"date":131,"cover":132,"coverAlt":133,"featured":14,"tags":134,"topic":20},"\u002Fsmart-home\u002Fhome-assistant-hallway-motion-light","תנועה במסדרון, אור שנדלק: אוטומציה ראשונה ב־Home Assistant","מדליקים תאורה כשמזוהה תנועה ומכבים אחרי שתי דקות ללא תנועה, עם YAML מלא והסבר על טריגרים ובדיקות.","2026-07-31","\u002Fimages\u002Fposts\u002Fhome-assistant-hallway-motion-light.svg","מסדרון ביתי עם חיישן תנועה ותאורת תקרה שנדלקת כשאדם נכנס",[16,50,85,51],{"path":136,"title":137,"description":138,"type":8,"level":9,"minutes":26,"date":139,"cover":140,"coverAlt":141,"featured":14,"tags":142,"topic":147},"\u002Ffullstack\u002Ffetch-http-errors-and-timeouts","למה Fetch לא זורק שגיאה כשהשרת מחזיר 404?","ההבדל בין כישלון רשת לתשובת HTTP, טיפול בגוף תשובה לא צפוי והגבלת זמן לבקשה, עם פונקציה שאפשר להריץ.","2026-07-26","\u002Fimages\u002Fposts\u002Ffetch-http-errors-and-timeouts.svg","בקשת Fetch מתפצלת לתשובת HTTP עם שגיאה ולכשל רשת או פסק זמן",[143,144,145,146],"JavaScript","Fetch","HTTP","Debugging","fullstack",{"path":149,"title":150,"description":151,"type":152,"level":25,"minutes":26,"date":153,"cover":154,"coverAlt":155,"featured":14,"tags":156,"topic":161},"\u002Fai\u002Frag-answering-from-your-documents","RAG: איך נותנים למודל לענות מתוך המסמכים שלכם","מה מחפשים לפני שמבקשים מהמודל לכתוב, למה קטעי המקור חשובים, ואיך בודקים אם התשובה באמת נשענת עליהם.","הסבר","2026-07-21","\u002Fimages\u002Fposts\u002Frag-answering-from-your-documents.svg","מסמכי מקור נבדקים בזכוכית מגדלת, קטע מתאים נבחר ועובר לכרטיס תשובה",[157,158,159,160],"AI","RAG","חיפוש","מסמכים","ai",{"path":163,"title":164,"description":165,"type":152,"level":25,"minutes":26,"date":166,"cover":167,"coverAlt":168,"featured":14,"tags":169,"topic":20},"\u002Fsmart-home\u002Fmatter-thread-zigbee-explained","Matter, Thread ו־Zigbee: מה ההבדל ומה צריך בבית?","שלושת השמות אינם מתארים את אותו סוג של דבר. הסבר על שכבות התקשורת, תפקידי הרכזת ובדיקת התאמה למערכת קיימת.","2026-07-16","\u002Fimages\u002Fposts\u002Fmatter-thread-zigbee-explained.svg","שתי קבוצות של מכשירי בית חכם, רשת Mesh ורכזת, עם שער שמקשר בין שכבות התקשורת",[170,171,41,172],"Matter","Thread","רשת ביתית",{"path":174,"title":175,"description":176,"type":8,"level":25,"minutes":177,"date":178,"cover":179,"coverAlt":180,"featured":14,"tags":181,"topic":147},"\u002Ffullstack\u002Fbrowser-to-server-save-form","מהדפדפן לשרת: בונים טופס שמירה ורואים מה קורה בדרך","טופס HTML, בקשת POST ושרת Node.js קטן. דוגמה מלאה שממחישה איך נתונים עוברים ואיפה בודקים אותם.",9,"2026-07-11","\u002Fimages\u002Fposts\u002Fbrowser-to-server-save-form.svg","טופס בדפדפן שולח מעטפת נתונים לשרת ומשם למסד הנתונים",[143,182,145,144],"Node.js",{"path":184,"title":185,"description":186,"type":152,"level":25,"minutes":56,"date":187,"cover":188,"coverAlt":189,"featured":190,"tags":191,"topic":161},"\u002Fai\u002Fai-agent-from-request-to-result","סוכן AI: מה קורה בין הבקשה לתוצאה","איך מודל שפה משתמש בכלים, מה ההבדל בין סוכן לתהליך קבוע ואיך מגדירים משימה שאפשר לבדוק.","2026-07-06","\u002Fimages\u002Fposts\u002Fai-agent-from-request-to-result.svg","בקשה עוברת דרך מנגנון בחירה לכלי חיפוש, מסמכים וביצוע, עד לתוצאה שנבדקה",true,[157,192,193,50],"Agents","Tool Calling",{"path":195,"title":196,"description":197,"type":8,"level":25,"minutes":198,"date":199,"cover":200,"coverAlt":201,"featured":14,"tags":202,"topic":20},"\u002Fsmart-home\u002Fsmart-home-first-steps-home-assistant","בית חכם מתחילים בצעד קטן: בחירת ציוד והתקנת Home Assistant","מה צריך לבית חכם ראשון, איך בוחרים בין Home Assistant OS ל-Container, ואיך מתקינים על Raspberry Pi, מחשב, מכונה וירטואלית או NAS.",24,"2026-07-01","\u002Fimages\u002Fposts\u002Fsmart-home-first-steps-home-assistant.svg","בית עם חיישן ותאורה, המחובר לשרת Home Assistant ולשתי אפשרויות התקנה: מערכת הפעלה וקונטיינר",[16,19,203,18,204,50],"התקנה","Raspberry Pi",{"id":206,"title":175,"body":207,"cover":179,"coverAlt":180,"date":178,"description":176,"draft":14,"extension":2564,"featured":14,"level":25,"meta":2565,"minutes":177,"navigation":190,"ogImage":2566,"path":174,"seo":2567,"sitemap":2568,"stem":2569,"tags":2570,"type":8,"updated":2571,"__hash__":2572},"posts\u002Ffullstack\u002Fbrowser-to-server-save-form.md",{"type":208,"value":209,"toc":2556},"minimark",[210,214,222,227,252,263,267,273,1606,1609,1627,1631,1635,2326,2333,2340,2344,2347,2361,2372,2379,2392,2396,2406,2409,2510,2519,2522,2526,2552],[211,212,213],"p",{},"לחיצה על ״שמירה״ מתחילה בממשק, אבל המידע צריך להגיע למקום שיודע לבדוק ולשמור אותו. בדרך יש בקשה, כתובת, גוף נתונים ותשובה. כשבונים דוגמה קטנה בלי framework (תשתית קוד מוכנה לבניית אפליקציות), קל לראות מה כל חלק עושה.",[211,215,216,217,221],{},"נכין טופס ששומר כותרת של פוסט. השרת יחזיר את הפוסט שנוצר, והממשק יציג אישור. השמירה בדוגמה היא ",[218,219,220],"strong",{},"בזיכרון בלבד",": המידע נעלם כשעוצרים את השרת. זה מאפשר להתרכז במסלול הבקשה לפני שמוסיפים מסד נתונים.",[223,224,226],"h2",{"id":225},"מה-צריך","מה צריך?",[228,229,230,239,242],"ul",{},[231,232,233,234,238],"li",{},"Node.js 22 ומעלה, זמין דרך הפקודה ",[235,236,237],"code",{},"node",".",[231,240,241],{},"דפדפן מודרני.",[231,243,244,245,248,249,238],{},"תיקייה חדשה עם שני קבצים: ",[235,246,247],{},"server.mjs"," ו־",[235,250,251],{},"index.html",[211,253,254,255,262],{},"אין צורך להתקין חבילות. הדוגמה משתמשת ב",[256,257,261],"a",{"href":258,"rel":259},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Fhttp.html",[260],"nofollow","מודול HTTP המובנה של Node.js"," וב־Fetch של הדפדפן.",[223,264,266],{"id":265},"השרת-לקבל-לבדוק-ולענות","השרת: לקבל, לבדוק ולענות",[211,268,269,270,272],{},"שמרו את הקוד הבא ב־",[235,271,247],{},":",[274,275,280],"pre",{"className":276,"code":277,"language":278,"meta":279,"style":279},"language-javascript shiki shiki-themes github-dark-contrast","import { createServer } from \"node:http\";\nimport { readFileSync } from \"node:fs\";\nimport { randomUUID } from \"node:crypto\";\n\nconst html = readFileSync(new URL(\".\u002Findex.html\", import.meta.url));\nconst posts = [];\nconst maxBodyBytes = 16 * 1024;\n\nfunction sendJson(res, status, data) {\n  res.writeHead(status, {\n    \"Content-Type\": \"application\u002Fjson; charset=utf-8\"\n  });\n  res.end(JSON.stringify(data));\n}\n\nconst server = createServer((req, res) => {\n  if (req.method === \"GET\" && req.url === \"\u002F\") {\n    res.writeHead(200, {\n      \"Content-Type\": \"text\u002Fhtml; charset=utf-8\"\n    });\n    res.end(html);\n    return;\n  }\n\n  if (req.method === \"GET\" && req.url === \"\u002Fapi\u002Fposts\") {\n    sendJson(res, 200, { posts });\n    return;\n  }\n\n  if (req.method !== \"POST\" || req.url !== \"\u002Fapi\u002Fposts\") {\n    sendJson(res, 404, {\n      error: { code: \"NOT_FOUND\", message: \"הכתובת לא נמצאה\" }\n    });\n    return;\n  }\n\n  const contentType = String(req.headers[\"content-type\"] ?? \"\")\n    .split(\";\")[0].trim().toLowerCase();\n\n  if (contentType !== \"application\u002Fjson\") {\n    req.resume();\n    sendJson(res, 415, {\n      error: { code: \"JSON_REQUIRED\", message: \"נדרש גוף JSON\" }\n    });\n    return;\n  }\n\n  const chunks = [];\n  let size = 0;\n  let tooLarge = false;\n\n  req.on(\"data\", chunk => {\n    if (tooLarge) return;\n    size += chunk.length;\n\n    if (size > maxBodyBytes) {\n      tooLarge = true;\n      chunks.length = 0;\n      sendJson(res, 413, {\n        error: { code: \"BODY_TOO_LARGE\", message: \"הבקשה גדולה מדי\" }\n      });\n      return;\n    }\n\n    chunks.push(chunk);\n  });\n\n  req.on(\"end\", () => {\n    if (tooLarge) return;\n\n    let body;\n    try {\n      body = JSON.parse(Buffer.concat(chunks).toString(\"utf8\"));\n    } catch {\n      sendJson(res, 400, {\n        error: { code: \"INVALID_JSON\", message: \"ה־JSON אינו תקין\" }\n      });\n      return;\n    }\n\n    const title = typeof body?.title === \"string\"\n      ? body.title.trim() : \"\";\n\n    if (!title || title.length > 120) {\n      sendJson(res, 400, {\n        error: {\n          code: \"INVALID_TITLE\",\n          message: \"הכותרת צריכה להכיל 1-120 תווים\"\n        }\n      });\n      return;\n    }\n\n    const post = { id: randomUUID(), title };\n    posts.push(post);\n    sendJson(res, 201, { post });\n  });\n\n  req.on(\"error\", () => {\n    if (!res.headersSent) {\n      sendJson(res, 400, {\n        error: { code: \"READ_FAILED\", message: \"קריאת הבקשה נכשלה\" }\n      });\n    }\n  });\n});\n\nserver.listen(3000, \"127.0.0.1\", () => {\n  console.log(\"Open http:\u002F\u002F127.0.0.1:3000\");\n});\n","javascript","",[235,281,282,305,320,335,341,385,398,418,422,449,461,473,479,500,505,510,542,570,586,597,603,613,621,627,631,653,667,674,679,684,708,720,738,743,750,755,760,792,827,832,847,858,870,885,890,897,902,907,919,936,951,956,980,994,1011,1016,1030,1043,1057,1070,1086,1092,1100,1106,1111,1123,1128,1133,1152,1163,1168,1177,1185,1221,1232,1244,1259,1264,1271,1276,1281,1303,1323,1328,1358,1369,1375,1387,1396,1402,1407,1414,1419,1424,1443,1454,1467,1472,1477,1495,1507,1518,1533,1538,1543,1548,1554,1559,1584,1601],{"__ignoreMap":279},[283,284,287,291,295,298,302],"span",{"class":285,"line":286},"line",1,[283,288,290],{"class":289},"snl16","import",[283,292,294],{"class":293},"s95oV"," { createServer } ",[283,296,297],{"class":289},"from",[283,299,301],{"class":300},"sU2Wk"," \"node:http\"",[283,303,304],{"class":293},";\n",[283,306,308,310,313,315,318],{"class":285,"line":307},2,[283,309,290],{"class":289},[283,311,312],{"class":293}," { readFileSync } ",[283,314,297],{"class":289},[283,316,317],{"class":300}," \"node:fs\"",[283,319,304],{"class":293},[283,321,323,325,328,330,333],{"class":285,"line":322},3,[283,324,290],{"class":289},[283,326,327],{"class":293}," { randomUUID } ",[283,329,297],{"class":289},[283,331,332],{"class":300}," \"node:crypto\"",[283,334,304],{"class":293},[283,336,338],{"class":285,"line":337},4,[283,339,340],{"emptyLinePlaceholder":190},"\n",[283,342,344,347,351,354,358,361,364,367,369,372,375,377,379,382],{"class":285,"line":343},5,[283,345,346],{"class":289},"const",[283,348,350],{"class":349},"sDLfK"," html",[283,352,353],{"class":289}," =",[283,355,357],{"class":356},"svObZ"," readFileSync",[283,359,360],{"class":293},"(",[283,362,363],{"class":289},"new",[283,365,366],{"class":356}," URL",[283,368,360],{"class":293},[283,370,371],{"class":300},"\".\u002Findex.html\"",[283,373,374],{"class":293},", ",[283,376,290],{"class":289},[283,378,238],{"class":293},[283,380,381],{"class":349},"meta",[283,383,384],{"class":293},".url));\n",[283,386,388,390,393,395],{"class":285,"line":387},6,[283,389,346],{"class":289},[283,391,392],{"class":349}," posts",[283,394,353],{"class":289},[283,396,397],{"class":293}," [];\n",[283,399,400,402,405,407,410,413,416],{"class":285,"line":56},[283,401,346],{"class":289},[283,403,404],{"class":349}," maxBodyBytes",[283,406,353],{"class":289},[283,408,409],{"class":349}," 16",[283,411,412],{"class":289}," *",[283,414,415],{"class":349}," 1024",[283,417,304],{"class":293},[283,419,420],{"class":285,"line":26},[283,421,340],{"emptyLinePlaceholder":190},[283,423,424,427,430,432,436,438,441,443,446],{"class":285,"line":177},[283,425,426],{"class":289},"function",[283,428,429],{"class":356}," sendJson",[283,431,360],{"class":293},[283,433,435],{"class":434},"s9osk","res",[283,437,374],{"class":293},[283,439,440],{"class":434},"status",[283,442,374],{"class":293},[283,444,445],{"class":434},"data",[283,447,448],{"class":293},") {\n",[283,450,452,455,458],{"class":285,"line":451},10,[283,453,454],{"class":293},"  res.",[283,456,457],{"class":356},"writeHead",[283,459,460],{"class":293},"(status, {\n",[283,462,464,467,470],{"class":285,"line":463},11,[283,465,466],{"class":300},"    \"Content-Type\"",[283,468,469],{"class":293},": ",[283,471,472],{"class":300},"\"application\u002Fjson; charset=utf-8\"\n",[283,474,476],{"class":285,"line":475},12,[283,477,478],{"class":293},"  });\n",[283,480,482,484,487,489,492,494,497],{"class":285,"line":481},13,[283,483,454],{"class":293},[283,485,486],{"class":356},"end",[283,488,360],{"class":293},[283,490,491],{"class":349},"JSON",[283,493,238],{"class":293},[283,495,496],{"class":356},"stringify",[283,498,499],{"class":293},"(data));\n",[283,501,502],{"class":285,"line":10},[283,503,504],{"class":293},"}\n",[283,506,508],{"class":285,"line":507},15,[283,509,340],{"emptyLinePlaceholder":190},[283,511,513,515,518,520,523,526,529,531,533,536,539],{"class":285,"line":512},16,[283,514,346],{"class":289},[283,516,517],{"class":349}," server",[283,519,353],{"class":289},[283,521,522],{"class":356}," createServer",[283,524,525],{"class":293},"((",[283,527,528],{"class":434},"req",[283,530,374],{"class":293},[283,532,435],{"class":434},[283,534,535],{"class":293},") ",[283,537,538],{"class":289},"=>",[283,540,541],{"class":293}," {\n",[283,543,545,548,551,554,557,560,563,565,568],{"class":285,"line":544},17,[283,546,547],{"class":289},"  if",[283,549,550],{"class":293}," (req.method ",[283,552,553],{"class":289},"===",[283,555,556],{"class":300}," \"GET\"",[283,558,559],{"class":289}," &&",[283,561,562],{"class":293}," req.url ",[283,564,553],{"class":289},[283,566,567],{"class":300}," \"\u002F\"",[283,569,448],{"class":293},[283,571,573,576,578,580,583],{"class":285,"line":572},18,[283,574,575],{"class":293},"    res.",[283,577,457],{"class":356},[283,579,360],{"class":293},[283,581,582],{"class":349},"200",[283,584,585],{"class":293},", {\n",[283,587,589,592,594],{"class":285,"line":588},19,[283,590,591],{"class":300},"      \"Content-Type\"",[283,593,469],{"class":293},[283,595,596],{"class":300},"\"text\u002Fhtml; charset=utf-8\"\n",[283,598,600],{"class":285,"line":599},20,[283,601,602],{"class":293},"    });\n",[283,604,606,608,610],{"class":285,"line":605},21,[283,607,575],{"class":293},[283,609,486],{"class":356},[283,611,612],{"class":293},"(html);\n",[283,614,616,619],{"class":285,"line":615},22,[283,617,618],{"class":289},"    return",[283,620,304],{"class":293},[283,622,624],{"class":285,"line":623},23,[283,625,626],{"class":293},"  }\n",[283,628,629],{"class":285,"line":198},[283,630,340],{"emptyLinePlaceholder":190},[283,632,634,636,638,640,642,644,646,648,651],{"class":285,"line":633},25,[283,635,547],{"class":289},[283,637,550],{"class":293},[283,639,553],{"class":289},[283,641,556],{"class":300},[283,643,559],{"class":289},[283,645,562],{"class":293},[283,647,553],{"class":289},[283,649,650],{"class":300}," \"\u002Fapi\u002Fposts\"",[283,652,448],{"class":293},[283,654,656,659,662,664],{"class":285,"line":655},26,[283,657,658],{"class":356},"    sendJson",[283,660,661],{"class":293},"(res, ",[283,663,582],{"class":349},[283,665,666],{"class":293},", { posts });\n",[283,668,670,672],{"class":285,"line":669},27,[283,671,618],{"class":289},[283,673,304],{"class":293},[283,675,677],{"class":285,"line":676},28,[283,678,626],{"class":293},[283,680,682],{"class":285,"line":681},29,[283,683,340],{"emptyLinePlaceholder":190},[283,685,687,689,691,694,697,700,702,704,706],{"class":285,"line":686},30,[283,688,547],{"class":289},[283,690,550],{"class":293},[283,692,693],{"class":289},"!==",[283,695,696],{"class":300}," \"POST\"",[283,698,699],{"class":289}," ||",[283,701,562],{"class":293},[283,703,693],{"class":289},[283,705,650],{"class":300},[283,707,448],{"class":293},[283,709,711,713,715,718],{"class":285,"line":710},31,[283,712,658],{"class":356},[283,714,661],{"class":293},[283,716,717],{"class":349},"404",[283,719,585],{"class":293},[283,721,723,726,729,732,735],{"class":285,"line":722},32,[283,724,725],{"class":293},"      error: { code: ",[283,727,728],{"class":300},"\"NOT_FOUND\"",[283,730,731],{"class":293},", message: ",[283,733,734],{"class":300},"\"הכתובת לא נמצאה\"",[283,736,737],{"class":293}," }\n",[283,739,741],{"class":285,"line":740},33,[283,742,602],{"class":293},[283,744,746,748],{"class":285,"line":745},34,[283,747,618],{"class":289},[283,749,304],{"class":293},[283,751,753],{"class":285,"line":752},35,[283,754,626],{"class":293},[283,756,758],{"class":285,"line":757},36,[283,759,340],{"emptyLinePlaceholder":190},[283,761,763,766,769,771,774,777,780,783,786,789],{"class":285,"line":762},37,[283,764,765],{"class":289},"  const",[283,767,768],{"class":349}," contentType",[283,770,353],{"class":289},[283,772,773],{"class":356}," String",[283,775,776],{"class":293},"(req.headers[",[283,778,779],{"class":300},"\"content-type\"",[283,781,782],{"class":293},"] ",[283,784,785],{"class":289},"??",[283,787,788],{"class":300}," \"\"",[283,790,791],{"class":293},")\n",[283,793,795,798,801,803,806,809,812,815,818,821,824],{"class":285,"line":794},38,[283,796,797],{"class":293},"    .",[283,799,800],{"class":356},"split",[283,802,360],{"class":293},[283,804,805],{"class":300},"\";\"",[283,807,808],{"class":293},")[",[283,810,811],{"class":349},"0",[283,813,814],{"class":293},"].",[283,816,817],{"class":356},"trim",[283,819,820],{"class":293},"().",[283,822,823],{"class":356},"toLowerCase",[283,825,826],{"class":293},"();\n",[283,828,830],{"class":285,"line":829},39,[283,831,340],{"emptyLinePlaceholder":190},[283,833,835,837,840,842,845],{"class":285,"line":834},40,[283,836,547],{"class":289},[283,838,839],{"class":293}," (contentType ",[283,841,693],{"class":289},[283,843,844],{"class":300}," \"application\u002Fjson\"",[283,846,448],{"class":293},[283,848,850,853,856],{"class":285,"line":849},41,[283,851,852],{"class":293},"    req.",[283,854,855],{"class":356},"resume",[283,857,826],{"class":293},[283,859,861,863,865,868],{"class":285,"line":860},42,[283,862,658],{"class":356},[283,864,661],{"class":293},[283,866,867],{"class":349},"415",[283,869,585],{"class":293},[283,871,873,875,878,880,883],{"class":285,"line":872},43,[283,874,725],{"class":293},[283,876,877],{"class":300},"\"JSON_REQUIRED\"",[283,879,731],{"class":293},[283,881,882],{"class":300},"\"נדרש גוף JSON\"",[283,884,737],{"class":293},[283,886,888],{"class":285,"line":887},44,[283,889,602],{"class":293},[283,891,893,895],{"class":285,"line":892},45,[283,894,618],{"class":289},[283,896,304],{"class":293},[283,898,900],{"class":285,"line":899},46,[283,901,626],{"class":293},[283,903,905],{"class":285,"line":904},47,[283,906,340],{"emptyLinePlaceholder":190},[283,908,910,912,915,917],{"class":285,"line":909},48,[283,911,765],{"class":289},[283,913,914],{"class":349}," chunks",[283,916,353],{"class":289},[283,918,397],{"class":293},[283,920,922,925,928,931,934],{"class":285,"line":921},49,[283,923,924],{"class":289},"  let",[283,926,927],{"class":293}," size ",[283,929,930],{"class":289},"=",[283,932,933],{"class":349}," 0",[283,935,304],{"class":293},[283,937,939,941,944,946,949],{"class":285,"line":938},50,[283,940,924],{"class":289},[283,942,943],{"class":293}," tooLarge ",[283,945,930],{"class":289},[283,947,948],{"class":349}," false",[283,950,304],{"class":293},[283,952,954],{"class":285,"line":953},51,[283,955,340],{"emptyLinePlaceholder":190},[283,957,959,962,965,967,970,972,975,978],{"class":285,"line":958},52,[283,960,961],{"class":293},"  req.",[283,963,964],{"class":356},"on",[283,966,360],{"class":293},[283,968,969],{"class":300},"\"data\"",[283,971,374],{"class":293},[283,973,974],{"class":434},"chunk",[283,976,977],{"class":289}," =>",[283,979,541],{"class":293},[283,981,983,986,989,992],{"class":285,"line":982},53,[283,984,985],{"class":289},"    if",[283,987,988],{"class":293}," (tooLarge) ",[283,990,991],{"class":289},"return",[283,993,304],{"class":293},[283,995,997,1000,1003,1006,1009],{"class":285,"line":996},54,[283,998,999],{"class":293},"    size ",[283,1001,1002],{"class":289},"+=",[283,1004,1005],{"class":293}," chunk.",[283,1007,1008],{"class":349},"length",[283,1010,304],{"class":293},[283,1012,1014],{"class":285,"line":1013},55,[283,1015,340],{"emptyLinePlaceholder":190},[283,1017,1019,1021,1024,1027],{"class":285,"line":1018},56,[283,1020,985],{"class":289},[283,1022,1023],{"class":293}," (size ",[283,1025,1026],{"class":289},">",[283,1028,1029],{"class":293}," maxBodyBytes) {\n",[283,1031,1033,1036,1038,1041],{"class":285,"line":1032},57,[283,1034,1035],{"class":293},"      tooLarge ",[283,1037,930],{"class":289},[283,1039,1040],{"class":349}," true",[283,1042,304],{"class":293},[283,1044,1046,1049,1051,1053,1055],{"class":285,"line":1045},58,[283,1047,1048],{"class":293},"      chunks.",[283,1050,1008],{"class":349},[283,1052,353],{"class":289},[283,1054,933],{"class":349},[283,1056,304],{"class":293},[283,1058,1060,1063,1065,1068],{"class":285,"line":1059},59,[283,1061,1062],{"class":356},"      sendJson",[283,1064,661],{"class":293},[283,1066,1067],{"class":349},"413",[283,1069,585],{"class":293},[283,1071,1073,1076,1079,1081,1084],{"class":285,"line":1072},60,[283,1074,1075],{"class":293},"        error: { code: ",[283,1077,1078],{"class":300},"\"BODY_TOO_LARGE\"",[283,1080,731],{"class":293},[283,1082,1083],{"class":300},"\"הבקשה גדולה מדי\"",[283,1085,737],{"class":293},[283,1087,1089],{"class":285,"line":1088},61,[283,1090,1091],{"class":293},"      });\n",[283,1093,1095,1098],{"class":285,"line":1094},62,[283,1096,1097],{"class":289},"      return",[283,1099,304],{"class":293},[283,1101,1103],{"class":285,"line":1102},63,[283,1104,1105],{"class":293},"    }\n",[283,1107,1109],{"class":285,"line":1108},64,[283,1110,340],{"emptyLinePlaceholder":190},[283,1112,1114,1117,1120],{"class":285,"line":1113},65,[283,1115,1116],{"class":293},"    chunks.",[283,1118,1119],{"class":356},"push",[283,1121,1122],{"class":293},"(chunk);\n",[283,1124,1126],{"class":285,"line":1125},66,[283,1127,478],{"class":293},[283,1129,1131],{"class":285,"line":1130},67,[283,1132,340],{"emptyLinePlaceholder":190},[283,1134,1136,1138,1140,1142,1145,1148,1150],{"class":285,"line":1135},68,[283,1137,961],{"class":293},[283,1139,964],{"class":356},[283,1141,360],{"class":293},[283,1143,1144],{"class":300},"\"end\"",[283,1146,1147],{"class":293},", () ",[283,1149,538],{"class":289},[283,1151,541],{"class":293},[283,1153,1155,1157,1159,1161],{"class":285,"line":1154},69,[283,1156,985],{"class":289},[283,1158,988],{"class":293},[283,1160,991],{"class":289},[283,1162,304],{"class":293},[283,1164,1166],{"class":285,"line":1165},70,[283,1167,340],{"emptyLinePlaceholder":190},[283,1169,1171,1174],{"class":285,"line":1170},71,[283,1172,1173],{"class":289},"    let",[283,1175,1176],{"class":293}," body;\n",[283,1178,1180,1183],{"class":285,"line":1179},72,[283,1181,1182],{"class":289},"    try",[283,1184,541],{"class":293},[283,1186,1188,1191,1193,1196,1198,1201,1204,1207,1210,1213,1215,1218],{"class":285,"line":1187},73,[283,1189,1190],{"class":293},"      body ",[283,1192,930],{"class":289},[283,1194,1195],{"class":349}," JSON",[283,1197,238],{"class":293},[283,1199,1200],{"class":356},"parse",[283,1202,1203],{"class":293},"(Buffer.",[283,1205,1206],{"class":356},"concat",[283,1208,1209],{"class":293},"(chunks).",[283,1211,1212],{"class":356},"toString",[283,1214,360],{"class":293},[283,1216,1217],{"class":300},"\"utf8\"",[283,1219,1220],{"class":293},"));\n",[283,1222,1224,1227,1230],{"class":285,"line":1223},74,[283,1225,1226],{"class":293},"    } ",[283,1228,1229],{"class":289},"catch",[283,1231,541],{"class":293},[283,1233,1235,1237,1239,1242],{"class":285,"line":1234},75,[283,1236,1062],{"class":356},[283,1238,661],{"class":293},[283,1240,1241],{"class":349},"400",[283,1243,585],{"class":293},[283,1245,1247,1249,1252,1254,1257],{"class":285,"line":1246},76,[283,1248,1075],{"class":293},[283,1250,1251],{"class":300},"\"INVALID_JSON\"",[283,1253,731],{"class":293},[283,1255,1256],{"class":300},"\"ה־JSON אינו תקין\"",[283,1258,737],{"class":293},[283,1260,1262],{"class":285,"line":1261},77,[283,1263,1091],{"class":293},[283,1265,1267,1269],{"class":285,"line":1266},78,[283,1268,1097],{"class":289},[283,1270,304],{"class":293},[283,1272,1274],{"class":285,"line":1273},79,[283,1275,1105],{"class":293},[283,1277,1279],{"class":285,"line":1278},80,[283,1280,340],{"emptyLinePlaceholder":190},[283,1282,1284,1287,1290,1292,1295,1298,1300],{"class":285,"line":1283},81,[283,1285,1286],{"class":289},"    const",[283,1288,1289],{"class":349}," title",[283,1291,353],{"class":289},[283,1293,1294],{"class":289}," typeof",[283,1296,1297],{"class":293}," body?.title ",[283,1299,553],{"class":289},[283,1301,1302],{"class":300}," \"string\"\n",[283,1304,1306,1309,1312,1314,1317,1319,1321],{"class":285,"line":1305},82,[283,1307,1308],{"class":289},"      ?",[283,1310,1311],{"class":293}," body.title.",[283,1313,817],{"class":356},[283,1315,1316],{"class":293},"() ",[283,1318,272],{"class":289},[283,1320,788],{"class":300},[283,1322,304],{"class":293},[283,1324,1326],{"class":285,"line":1325},83,[283,1327,340],{"emptyLinePlaceholder":190},[283,1329,1331,1333,1336,1339,1342,1345,1348,1350,1353,1356],{"class":285,"line":1330},84,[283,1332,985],{"class":289},[283,1334,1335],{"class":293}," (",[283,1337,1338],{"class":289},"!",[283,1340,1341],{"class":293},"title ",[283,1343,1344],{"class":289},"||",[283,1346,1347],{"class":293}," title.",[283,1349,1008],{"class":349},[283,1351,1352],{"class":289}," >",[283,1354,1355],{"class":349}," 120",[283,1357,448],{"class":293},[283,1359,1361,1363,1365,1367],{"class":285,"line":1360},85,[283,1362,1062],{"class":356},[283,1364,661],{"class":293},[283,1366,1241],{"class":349},[283,1368,585],{"class":293},[283,1370,1372],{"class":285,"line":1371},86,[283,1373,1374],{"class":293},"        error: {\n",[283,1376,1378,1381,1384],{"class":285,"line":1377},87,[283,1379,1380],{"class":293},"          code: ",[283,1382,1383],{"class":300},"\"INVALID_TITLE\"",[283,1385,1386],{"class":293},",\n",[283,1388,1390,1393],{"class":285,"line":1389},88,[283,1391,1392],{"class":293},"          message: ",[283,1394,1395],{"class":300},"\"הכותרת צריכה להכיל 1-120 תווים\"\n",[283,1397,1399],{"class":285,"line":1398},89,[283,1400,1401],{"class":293},"        }\n",[283,1403,1405],{"class":285,"line":1404},90,[283,1406,1091],{"class":293},[283,1408,1410,1412],{"class":285,"line":1409},91,[283,1411,1097],{"class":289},[283,1413,304],{"class":293},[283,1415,1417],{"class":285,"line":1416},92,[283,1418,1105],{"class":293},[283,1420,1422],{"class":285,"line":1421},93,[283,1423,340],{"emptyLinePlaceholder":190},[283,1425,1427,1429,1432,1434,1437,1440],{"class":285,"line":1426},94,[283,1428,1286],{"class":289},[283,1430,1431],{"class":349}," post",[283,1433,353],{"class":289},[283,1435,1436],{"class":293}," { id: ",[283,1438,1439],{"class":356},"randomUUID",[283,1441,1442],{"class":293},"(), title };\n",[283,1444,1446,1449,1451],{"class":285,"line":1445},95,[283,1447,1448],{"class":293},"    posts.",[283,1450,1119],{"class":356},[283,1452,1453],{"class":293},"(post);\n",[283,1455,1457,1459,1461,1464],{"class":285,"line":1456},96,[283,1458,658],{"class":356},[283,1460,661],{"class":293},[283,1462,1463],{"class":349},"201",[283,1465,1466],{"class":293},", { post });\n",[283,1468,1470],{"class":285,"line":1469},97,[283,1471,478],{"class":293},[283,1473,1475],{"class":285,"line":1474},98,[283,1476,340],{"emptyLinePlaceholder":190},[283,1478,1480,1482,1484,1486,1489,1491,1493],{"class":285,"line":1479},99,[283,1481,961],{"class":293},[283,1483,964],{"class":356},[283,1485,360],{"class":293},[283,1487,1488],{"class":300},"\"error\"",[283,1490,1147],{"class":293},[283,1492,538],{"class":289},[283,1494,541],{"class":293},[283,1496,1498,1500,1502,1504],{"class":285,"line":1497},100,[283,1499,985],{"class":289},[283,1501,1335],{"class":293},[283,1503,1338],{"class":289},[283,1505,1506],{"class":293},"res.headersSent) {\n",[283,1508,1510,1512,1514,1516],{"class":285,"line":1509},101,[283,1511,1062],{"class":356},[283,1513,661],{"class":293},[283,1515,1241],{"class":349},[283,1517,585],{"class":293},[283,1519,1521,1523,1526,1528,1531],{"class":285,"line":1520},102,[283,1522,1075],{"class":293},[283,1524,1525],{"class":300},"\"READ_FAILED\"",[283,1527,731],{"class":293},[283,1529,1530],{"class":300},"\"קריאת הבקשה נכשלה\"",[283,1532,737],{"class":293},[283,1534,1536],{"class":285,"line":1535},103,[283,1537,1091],{"class":293},[283,1539,1541],{"class":285,"line":1540},104,[283,1542,1105],{"class":293},[283,1544,1546],{"class":285,"line":1545},105,[283,1547,478],{"class":293},[283,1549,1551],{"class":285,"line":1550},106,[283,1552,1553],{"class":293},"});\n",[283,1555,1557],{"class":285,"line":1556},107,[283,1558,340],{"emptyLinePlaceholder":190},[283,1560,1562,1565,1568,1570,1573,1575,1578,1580,1582],{"class":285,"line":1561},108,[283,1563,1564],{"class":293},"server.",[283,1566,1567],{"class":356},"listen",[283,1569,360],{"class":293},[283,1571,1572],{"class":349},"3000",[283,1574,374],{"class":293},[283,1576,1577],{"class":300},"\"127.0.0.1\"",[283,1579,1147],{"class":293},[283,1581,538],{"class":289},[283,1583,541],{"class":293},[283,1585,1587,1590,1593,1595,1598],{"class":285,"line":1586},109,[283,1588,1589],{"class":293},"  console.",[283,1591,1592],{"class":356},"log",[283,1594,360],{"class":293},[283,1596,1597],{"class":300},"\"Open http:\u002F\u002F127.0.0.1:3000\"",[283,1599,1600],{"class":293},");\n",[283,1602,1604],{"class":285,"line":1603},110,[283,1605,1553],{"class":293},[211,1607,1608],{},"השרת מכיר שלוש בקשות: הצגת הדף, קבלת רשימת הפוסטים ויצירת פוסט. ביצירה הוא בודק את סוג התוכן, מגביל את גודל הגוף, מפענח JSON ובודק את הכותרת. רק אחרי הבדיקות הוא מוסיף רשומה למערך.",[211,1610,1611,1612,1614,1615,1617,1618,1622,1623,238],{},"קוד הסטטוס ",[235,1613,1463],{}," מציין שנוצר משאב חדש. קוד ",[235,1616,1241],{}," מציין בעיה בבקשת הלקוח. כאן משתמשים בו עבור JSON לא תקין או כותרת שאינה עומדת בכללים. אלו המשמעויות המתוארות בתיעוד MDN ל־",[256,1619,1463],{"href":1620,"rel":1621},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FReference\u002FStatus\u002F201",[260]," ול־",[256,1624,1241],{"href":1625,"rel":1626},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTTP\u002FReference\u002FStatus\u002F400",[260],[223,1628,1630],{"id":1629},"הממשק-לשלוח-ולהציג-תוצאה","הממשק: לשלוח ולהציג תוצאה",[211,1632,269,1633,272],{},[235,1634,251],{},[274,1636,1640],{"className":1637,"code":1638,"language":1639,"meta":279,"style":279},"language-html shiki shiki-themes github-dark-contrast","\u003C!doctype html>\n\u003Chtml lang=\"he\" dir=\"rtl\">\n\u003Chead>\n  \u003Cmeta charset=\"utf-8\">\n  \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  \u003Ctitle>שמירת פוסט\u003C\u002Ftitle>\n\u003C\u002Fhead>\n\u003Cbody>\n  \u003Ch1>פוסט חדש\u003C\u002Fh1>\n  \u003Cform id=\"post-form\">\n    \u003Clabel for=\"title\">כותרת\u003C\u002Flabel>\n    \u003Cinput id=\"title\" name=\"title\" required maxlength=\"120\">\n    \u003Cbutton id=\"save\" type=\"submit\">שמירה\u003C\u002Fbutton>\n  \u003C\u002Fform>\n  \u003Cp id=\"message\" role=\"status\">\u003C\u002Fp>\n\n  \u003Cscript>\n    const form = document.querySelector(\"#post-form\");\n    const input = document.querySelector(\"#title\");\n    const button = document.querySelector(\"#save\");\n    const message = document.querySelector(\"#message\");\n\n    form.addEventListener(\"submit\", async event => {\n      event.preventDefault();\n      button.disabled = true;\n      message.textContent = \"שומר...\";\n\n      try {\n        const response = await fetch(\"\u002Fapi\u002Fposts\", {\n          method: \"POST\",\n          headers: { \"Content-Type\": \"application\u002Fjson\" },\n          body: JSON.stringify({ title: input.value })\n        });\n\n        const data = await response.json();\n\n        if (!response.ok) {\n          throw new Error(data.error?.message ?? \"השמירה נכשלה\");\n        }\n\n        message.textContent = `נשמר: ${data.post.title}`;\n        form.reset();\n      } catch (error) {\n        message.textContent = error.message;\n      } finally {\n        button.disabled = false;\n      }\n    });\n  \u003C\u002Fscript>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n","html",[235,1641,1642,1656,1681,1690,1707,1731,1745,1754,1763,1777,1794,1817,1849,1878,1887,1915,1919,1928,1950,1970,1990,2010,2014,2038,2048,2059,2071,2075,2082,2105,2115,2131,2145,2150,2154,2173,2177,2189,2210,2214,2218,2244,2254,2264,2273,2282,2293,2298,2302,2310,2318],{"__ignoreMap":279},[283,1643,1644,1647,1651,1653],{"class":285,"line":286},[283,1645,1646],{"class":293},"\u003C!",[283,1648,1650],{"class":1649},"s4JwU","doctype",[283,1652,350],{"class":356},[283,1654,1655],{"class":293},">\n",[283,1657,1658,1661,1663,1666,1668,1671,1674,1676,1679],{"class":285,"line":307},[283,1659,1660],{"class":293},"\u003C",[283,1662,1639],{"class":1649},[283,1664,1665],{"class":356}," lang",[283,1667,930],{"class":293},[283,1669,1670],{"class":300},"\"he\"",[283,1672,1673],{"class":356}," dir",[283,1675,930],{"class":293},[283,1677,1678],{"class":300},"\"rtl\"",[283,1680,1655],{"class":293},[283,1682,1683,1685,1688],{"class":285,"line":322},[283,1684,1660],{"class":293},[283,1686,1687],{"class":1649},"head",[283,1689,1655],{"class":293},[283,1691,1692,1695,1697,1700,1702,1705],{"class":285,"line":337},[283,1693,1694],{"class":293},"  \u003C",[283,1696,381],{"class":1649},[283,1698,1699],{"class":356}," charset",[283,1701,930],{"class":293},[283,1703,1704],{"class":300},"\"utf-8\"",[283,1706,1655],{"class":293},[283,1708,1709,1711,1713,1716,1718,1721,1724,1726,1729],{"class":285,"line":343},[283,1710,1694],{"class":293},[283,1712,381],{"class":1649},[283,1714,1715],{"class":356}," name",[283,1717,930],{"class":293},[283,1719,1720],{"class":300},"\"viewport\"",[283,1722,1723],{"class":356}," content",[283,1725,930],{"class":293},[283,1727,1728],{"class":300},"\"width=device-width, initial-scale=1\"",[283,1730,1655],{"class":293},[283,1732,1733,1735,1738,1741,1743],{"class":285,"line":387},[283,1734,1694],{"class":293},[283,1736,1737],{"class":1649},"title",[283,1739,1740],{"class":293},">שמירת פוסט\u003C\u002F",[283,1742,1737],{"class":1649},[283,1744,1655],{"class":293},[283,1746,1747,1750,1752],{"class":285,"line":56},[283,1748,1749],{"class":293},"\u003C\u002F",[283,1751,1687],{"class":1649},[283,1753,1655],{"class":293},[283,1755,1756,1758,1761],{"class":285,"line":26},[283,1757,1660],{"class":293},[283,1759,1760],{"class":1649},"body",[283,1762,1655],{"class":293},[283,1764,1765,1767,1770,1773,1775],{"class":285,"line":177},[283,1766,1694],{"class":293},[283,1768,1769],{"class":1649},"h1",[283,1771,1772],{"class":293},">פוסט חדש\u003C\u002F",[283,1774,1769],{"class":1649},[283,1776,1655],{"class":293},[283,1778,1779,1781,1784,1787,1789,1792],{"class":285,"line":451},[283,1780,1694],{"class":293},[283,1782,1783],{"class":1649},"form",[283,1785,1786],{"class":356}," id",[283,1788,930],{"class":293},[283,1790,1791],{"class":300},"\"post-form\"",[283,1793,1655],{"class":293},[283,1795,1796,1799,1802,1805,1807,1810,1813,1815],{"class":285,"line":463},[283,1797,1798],{"class":293},"    \u003C",[283,1800,1801],{"class":1649},"label",[283,1803,1804],{"class":356}," for",[283,1806,930],{"class":293},[283,1808,1809],{"class":300},"\"title\"",[283,1811,1812],{"class":293},">כותרת\u003C\u002F",[283,1814,1801],{"class":1649},[283,1816,1655],{"class":293},[283,1818,1819,1821,1824,1826,1828,1830,1832,1834,1836,1839,1842,1844,1847],{"class":285,"line":475},[283,1820,1798],{"class":293},[283,1822,1823],{"class":1649},"input",[283,1825,1786],{"class":356},[283,1827,930],{"class":293},[283,1829,1809],{"class":300},[283,1831,1715],{"class":356},[283,1833,930],{"class":293},[283,1835,1809],{"class":300},[283,1837,1838],{"class":356}," required",[283,1840,1841],{"class":356}," maxlength",[283,1843,930],{"class":293},[283,1845,1846],{"class":300},"\"120\"",[283,1848,1655],{"class":293},[283,1850,1851,1853,1856,1858,1860,1863,1866,1868,1871,1874,1876],{"class":285,"line":481},[283,1852,1798],{"class":293},[283,1854,1855],{"class":1649},"button",[283,1857,1786],{"class":356},[283,1859,930],{"class":293},[283,1861,1862],{"class":300},"\"save\"",[283,1864,1865],{"class":356}," type",[283,1867,930],{"class":293},[283,1869,1870],{"class":300},"\"submit\"",[283,1872,1873],{"class":293},">שמירה\u003C\u002F",[283,1875,1855],{"class":1649},[283,1877,1655],{"class":293},[283,1879,1880,1883,1885],{"class":285,"line":10},[283,1881,1882],{"class":293},"  \u003C\u002F",[283,1884,1783],{"class":1649},[283,1886,1655],{"class":293},[283,1888,1889,1891,1893,1895,1897,1900,1903,1905,1908,1911,1913],{"class":285,"line":507},[283,1890,1694],{"class":293},[283,1892,211],{"class":1649},[283,1894,1786],{"class":356},[283,1896,930],{"class":293},[283,1898,1899],{"class":300},"\"message\"",[283,1901,1902],{"class":356}," role",[283,1904,930],{"class":293},[283,1906,1907],{"class":300},"\"status\"",[283,1909,1910],{"class":293},">\u003C\u002F",[283,1912,211],{"class":1649},[283,1914,1655],{"class":293},[283,1916,1917],{"class":285,"line":512},[283,1918,340],{"emptyLinePlaceholder":190},[283,1920,1921,1923,1926],{"class":285,"line":544},[283,1922,1694],{"class":293},[283,1924,1925],{"class":1649},"script",[283,1927,1655],{"class":293},[283,1929,1930,1932,1935,1937,1940,1943,1945,1948],{"class":285,"line":572},[283,1931,1286],{"class":289},[283,1933,1934],{"class":349}," form",[283,1936,353],{"class":289},[283,1938,1939],{"class":293}," document.",[283,1941,1942],{"class":356},"querySelector",[283,1944,360],{"class":293},[283,1946,1947],{"class":300},"\"#post-form\"",[283,1949,1600],{"class":293},[283,1951,1952,1954,1957,1959,1961,1963,1965,1968],{"class":285,"line":588},[283,1953,1286],{"class":289},[283,1955,1956],{"class":349}," input",[283,1958,353],{"class":289},[283,1960,1939],{"class":293},[283,1962,1942],{"class":356},[283,1964,360],{"class":293},[283,1966,1967],{"class":300},"\"#title\"",[283,1969,1600],{"class":293},[283,1971,1972,1974,1977,1979,1981,1983,1985,1988],{"class":285,"line":599},[283,1973,1286],{"class":289},[283,1975,1976],{"class":349}," button",[283,1978,353],{"class":289},[283,1980,1939],{"class":293},[283,1982,1942],{"class":356},[283,1984,360],{"class":293},[283,1986,1987],{"class":300},"\"#save\"",[283,1989,1600],{"class":293},[283,1991,1992,1994,1997,1999,2001,2003,2005,2008],{"class":285,"line":605},[283,1993,1286],{"class":289},[283,1995,1996],{"class":349}," message",[283,1998,353],{"class":289},[283,2000,1939],{"class":293},[283,2002,1942],{"class":356},[283,2004,360],{"class":293},[283,2006,2007],{"class":300},"\"#message\"",[283,2009,1600],{"class":293},[283,2011,2012],{"class":285,"line":615},[283,2013,340],{"emptyLinePlaceholder":190},[283,2015,2016,2019,2022,2024,2026,2028,2031,2034,2036],{"class":285,"line":623},[283,2017,2018],{"class":293},"    form.",[283,2020,2021],{"class":356},"addEventListener",[283,2023,360],{"class":293},[283,2025,1870],{"class":300},[283,2027,374],{"class":293},[283,2029,2030],{"class":289},"async",[283,2032,2033],{"class":434}," event",[283,2035,977],{"class":289},[283,2037,541],{"class":293},[283,2039,2040,2043,2046],{"class":285,"line":198},[283,2041,2042],{"class":293},"      event.",[283,2044,2045],{"class":356},"preventDefault",[283,2047,826],{"class":293},[283,2049,2050,2053,2055,2057],{"class":285,"line":633},[283,2051,2052],{"class":293},"      button.disabled ",[283,2054,930],{"class":289},[283,2056,1040],{"class":349},[283,2058,304],{"class":293},[283,2060,2061,2064,2066,2069],{"class":285,"line":655},[283,2062,2063],{"class":293},"      message.textContent ",[283,2065,930],{"class":289},[283,2067,2068],{"class":300}," \"שומר...\"",[283,2070,304],{"class":293},[283,2072,2073],{"class":285,"line":669},[283,2074,340],{"emptyLinePlaceholder":190},[283,2076,2077,2080],{"class":285,"line":676},[283,2078,2079],{"class":289},"      try",[283,2081,541],{"class":293},[283,2083,2084,2087,2090,2092,2095,2098,2100,2103],{"class":285,"line":681},[283,2085,2086],{"class":289},"        const",[283,2088,2089],{"class":349}," response",[283,2091,353],{"class":289},[283,2093,2094],{"class":289}," await",[283,2096,2097],{"class":356}," fetch",[283,2099,360],{"class":293},[283,2101,2102],{"class":300},"\"\u002Fapi\u002Fposts\"",[283,2104,585],{"class":293},[283,2106,2107,2110,2113],{"class":285,"line":686},[283,2108,2109],{"class":293},"          method: ",[283,2111,2112],{"class":300},"\"POST\"",[283,2114,1386],{"class":293},[283,2116,2117,2120,2123,2125,2128],{"class":285,"line":710},[283,2118,2119],{"class":293},"          headers: { ",[283,2121,2122],{"class":300},"\"Content-Type\"",[283,2124,469],{"class":293},[283,2126,2127],{"class":300},"\"application\u002Fjson\"",[283,2129,2130],{"class":293}," },\n",[283,2132,2133,2136,2138,2140,2142],{"class":285,"line":722},[283,2134,2135],{"class":293},"          body: ",[283,2137,491],{"class":349},[283,2139,238],{"class":293},[283,2141,496],{"class":356},[283,2143,2144],{"class":293},"({ title: input.value })\n",[283,2146,2147],{"class":285,"line":740},[283,2148,2149],{"class":293},"        });\n",[283,2151,2152],{"class":285,"line":745},[283,2153,340],{"emptyLinePlaceholder":190},[283,2155,2156,2158,2161,2163,2165,2168,2171],{"class":285,"line":752},[283,2157,2086],{"class":289},[283,2159,2160],{"class":349}," data",[283,2162,353],{"class":289},[283,2164,2094],{"class":289},[283,2166,2167],{"class":293}," response.",[283,2169,2170],{"class":356},"json",[283,2172,826],{"class":293},[283,2174,2175],{"class":285,"line":757},[283,2176,340],{"emptyLinePlaceholder":190},[283,2178,2179,2182,2184,2186],{"class":285,"line":762},[283,2180,2181],{"class":289},"        if",[283,2183,1335],{"class":293},[283,2185,1338],{"class":289},[283,2187,2188],{"class":293},"response.ok) {\n",[283,2190,2191,2194,2197,2200,2203,2205,2208],{"class":285,"line":794},[283,2192,2193],{"class":289},"          throw",[283,2195,2196],{"class":289}," new",[283,2198,2199],{"class":356}," Error",[283,2201,2202],{"class":293},"(data.error?.message ",[283,2204,785],{"class":289},[283,2206,2207],{"class":300}," \"השמירה נכשלה\"",[283,2209,1600],{"class":293},[283,2211,2212],{"class":285,"line":829},[283,2213,1401],{"class":293},[283,2215,2216],{"class":285,"line":834},[283,2217,340],{"emptyLinePlaceholder":190},[283,2219,2220,2223,2225,2228,2230,2232,2235,2237,2239,2242],{"class":285,"line":849},[283,2221,2222],{"class":293},"        message.textContent ",[283,2224,930],{"class":289},[283,2226,2227],{"class":300}," `נשמר: ${",[283,2229,445],{"class":293},[283,2231,238],{"class":300},[283,2233,2234],{"class":293},"post",[283,2236,238],{"class":300},[283,2238,1737],{"class":293},[283,2240,2241],{"class":300},"}`",[283,2243,304],{"class":293},[283,2245,2246,2249,2252],{"class":285,"line":860},[283,2247,2248],{"class":293},"        form.",[283,2250,2251],{"class":356},"reset",[283,2253,826],{"class":293},[283,2255,2256,2259,2261],{"class":285,"line":872},[283,2257,2258],{"class":293},"      } ",[283,2260,1229],{"class":289},[283,2262,2263],{"class":293}," (error) {\n",[283,2265,2266,2268,2270],{"class":285,"line":887},[283,2267,2222],{"class":293},[283,2269,930],{"class":289},[283,2271,2272],{"class":293}," error.message;\n",[283,2274,2275,2277,2280],{"class":285,"line":892},[283,2276,2258],{"class":293},[283,2278,2279],{"class":289},"finally",[283,2281,541],{"class":293},[283,2283,2284,2287,2289,2291],{"class":285,"line":899},[283,2285,2286],{"class":293},"        button.disabled ",[283,2288,930],{"class":289},[283,2290,948],{"class":349},[283,2292,304],{"class":293},[283,2294,2295],{"class":285,"line":904},[283,2296,2297],{"class":293},"      }\n",[283,2299,2300],{"class":285,"line":909},[283,2301,602],{"class":293},[283,2303,2304,2306,2308],{"class":285,"line":921},[283,2305,1882],{"class":293},[283,2307,1925],{"class":1649},[283,2309,1655],{"class":293},[283,2311,2312,2314,2316],{"class":285,"line":938},[283,2313,1749],{"class":293},[283,2315,1760],{"class":1649},[283,2317,1655],{"class":293},[283,2319,2320,2322,2324],{"class":285,"line":953},[283,2321,1749],{"class":293},[283,2323,1639],{"class":1649},[283,2325,1655],{"class":293},[211,2327,2328,2329,2332],{},"הכותרת נשלחת כמחרוזת בתוך JSON. התוצאה מוצגת באמצעות ",[235,2330,2331],{},"textContent",", כך שהכותרת נכתבת כטקסט ולא מתפרשת כ־HTML. השדה מתנקה רק אחרי הצלחה. כישלון משאיר את מה שהמשתמש כתב, כדי שיוכל לתקן או לנסות שוב.",[211,2334,2335,2336,2339],{},"הקוד מניח שהתשובות מהשרת הזה הן JSON, כפי שמוגדר בדוגמה. במערכת רחבה יותר גם שרת ביניים יכול להחזיר HTML או גוף ריק. ",[256,2337,2338],{"href":136},"המאמר על טיפול בשגיאות Fetch"," מטפל גם במקרים האלה.",[223,2341,2343],{"id":2342},"מריצים-ובודקים","מריצים ובודקים",[211,2345,2346],{},"מתוך התיקייה עם שני הקבצים, הריצו:",[274,2348,2352],{"className":2349,"code":2350,"language":2351,"meta":279,"style":279},"language-bash shiki shiki-themes github-dark-contrast","node server.mjs\n","bash",[235,2353,2354],{"__ignoreMap":279},[283,2355,2356,2358],{"class":285,"line":286},[283,2357,237],{"class":356},[283,2359,2360],{"class":300}," server.mjs\n",[211,2362,2363,2364,2367,2368,2371],{},"פתחו בדפדפן את ",[235,2365,2366],{},"http:\u002F\u002F127.0.0.1:3000",". אל תפתחו את קובץ ה־HTML ישירות: השרת מגיש את הדף ואת ה־API מאותו מקור, ולכן הכתובת היחסית ",[235,2369,2370],{},"\u002Fapi\u002Fposts"," מגיעה אליו בלי צורך בהגדרות CORS (הכללים שמתירים לדף לפנות לשרת ממקור אחר).",[211,2373,2374,2375,2378],{},"הקלידו כותרת ולחצו על ״שמירה״. אמורה להופיע הודעה עם הכותרת שנשמרה. פתיחת ",[235,2376,2377],{},"http:\u002F\u002F127.0.0.1:3000\u002Fapi\u002Fposts"," מציגה את הרשומות שהשרת מחזיק בזיכרון.",[211,2380,2381,2382,2384,2385,2388,2389,2391],{},"כעת פתחו את כלי הפיתוח של הדפדפן ובחרו בלשונית Network. שמרו פוסט נוסף וחפשו את הבקשה ל־",[235,2383,2370],{},". אפשר לראות את שיטת ",[235,2386,2387],{},"POST",", את הנתונים שנשלחו ואת תגובת ",[235,2390,1463],{}," עם המזהה שנוצר.",[223,2393,2395],{"id":2394},"למה-בודקים-גם-בדפדפן-וגם-בשרת","למה בודקים גם בדפדפן וגם בשרת?",[211,2397,2398,2399,248,2402,2405],{},"המאפיינים ",[235,2400,2401],{},"required",[235,2403,2404],{},"maxlength"," עוזרים למשתמש למלא את הטופס. הם אינם מחליפים בדיקה בשרת: לקוח אחר יכול לשלוח בקשה ישירות בלי להשתמש בטופס הזה.",[211,2407,2408],{},"אפשר לבדוק זאת מתוך ה־Console של הדף:",[274,2410,2412],{"className":276,"code":2411,"language":278,"meta":279,"style":279},"const response = await fetch(\"\u002Fapi\u002Fposts\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application\u002Fjson\" },\n  body: JSON.stringify({ title: \"   \" })\n});\n\nconsole.log(response.status);\nconsole.log(await response.json());\n",[235,2413,2414,2432,2441,2454,2474,2478,2482,2492],{"__ignoreMap":279},[283,2415,2416,2418,2420,2422,2424,2426,2428,2430],{"class":285,"line":286},[283,2417,346],{"class":289},[283,2419,2089],{"class":349},[283,2421,353],{"class":289},[283,2423,2094],{"class":289},[283,2425,2097],{"class":356},[283,2427,360],{"class":293},[283,2429,2102],{"class":300},[283,2431,585],{"class":293},[283,2433,2434,2437,2439],{"class":285,"line":307},[283,2435,2436],{"class":293},"  method: ",[283,2438,2112],{"class":300},[283,2440,1386],{"class":293},[283,2442,2443,2446,2448,2450,2452],{"class":285,"line":322},[283,2444,2445],{"class":293},"  headers: { ",[283,2447,2122],{"class":300},[283,2449,469],{"class":293},[283,2451,2127],{"class":300},[283,2453,2130],{"class":293},[283,2455,2456,2459,2461,2463,2465,2468,2471],{"class":285,"line":337},[283,2457,2458],{"class":293},"  body: ",[283,2460,491],{"class":349},[283,2462,238],{"class":293},[283,2464,496],{"class":356},[283,2466,2467],{"class":293},"({ title: ",[283,2469,2470],{"class":300},"\"   \"",[283,2472,2473],{"class":293}," })\n",[283,2475,2476],{"class":285,"line":343},[283,2477,1553],{"class":293},[283,2479,2480],{"class":285,"line":387},[283,2481,340],{"emptyLinePlaceholder":190},[283,2483,2484,2487,2489],{"class":285,"line":56},[283,2485,2486],{"class":293},"console.",[283,2488,1592],{"class":356},[283,2490,2491],{"class":293},"(response.status);\n",[283,2493,2494,2496,2498,2500,2503,2505,2507],{"class":285,"line":26},[283,2495,2486],{"class":293},[283,2497,1592],{"class":356},[283,2499,360],{"class":293},[283,2501,2502],{"class":289},"await",[283,2504,2167],{"class":293},[283,2506,2170],{"class":356},[283,2508,2509],{"class":293},"());\n",[211,2511,2512,2513,2515,2516,2518],{},"הסטטוס הוא ",[235,2514,1241],{},", והתגובה מסבירה שהכותרת אינה תקינה. השרת מסיר את הרווחים עם ",[235,2517,817],{},", ולכן הם אינם נחשבים לכותרת.",[211,2520,2521],{},"השרת בדוגמה מאזין רק למחשב המקומי. הוא אינו כולל משתמשים, הרשאות או אחסון קבוע, ואינו מיועד להפעלה כאתר ציבורי. אחרי שמבינים את מסלול הבקשה, אפשר להוסיף מסד נתונים ולבדוק מה קורה כשהשמירה עצמה נכשלת.",[223,2523,2525],{"id":2524},"לקריאה-נוספת","לקריאה נוספת",[228,2527,2528,2534,2541,2547],{},[231,2529,2530,238],{},[256,2531,2533],{"href":258,"rel":2532},[260],"Node.js: שרתי HTTP ובקשות נכנסות",[231,2535,2536,238],{},[256,2537,2540],{"href":2538,"rel":2539},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FFetch_API\u002FUsing_Fetch",[260],"MDN: עבודה עם Fetch",[231,2542,2543,238],{},[256,2544,2546],{"href":1620,"rel":2545},[260],"MDN: סטטוס 201",[231,2548,2549,238],{},[256,2550,2551],{"href":136},"למה Fetch לא זורק שגיאה על כל כישלון",[2553,2554,2555],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}",{"title":279,"searchDepth":307,"depth":307,"links":2557},[2558,2559,2560,2561,2562,2563],{"id":225,"depth":307,"text":226},{"id":265,"depth":307,"text":266},{"id":1629,"depth":307,"text":1630},{"id":2342,"depth":307,"text":2343},{"id":2394,"depth":307,"text":2395},{"id":2524,"depth":307,"text":2525},"md",{},"\u002Fimages\u002Fposts\u002Fbrowser-to-server-save-form.png",{"title":175,"description":176},{"loc":174},"fullstack\u002Fbrowser-to-server-save-form",[143,182,145,144],null,"OyXE0kKyVEBo0RliGkaHQ9nNb2Uwh650FWPNOM5QTxo",1791147941810]