╭ changed ─────────╮ │src/event/User.zig│ ╰──────────────────╯ ╭──────────────────────────────────────────────────────────╮ │12 enable_ansi: bool = false, │ │13 │ │14 const Self = @This(); │ │15 + │ │16 +pub const name_max_len = 32; │ │17 │ │18 // the subset of a user that's safe to hand to clients│ │19 pub const Safe = struct { │ ╰──────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────╮ │42 const name_to_user_id = try DB.HashMap(.read_write).init(name_to_user_id_cursor);│ │43 │ │44 if (event_maybe) |event| { │ │45 + if (event.name.len > name_max_len) return error.NameTooLong; │ │46 + │ │47 // if this event_id already maps to a user with a different name, │ │48 // drop the stale name->id entry first │ │49 if (try event_id_to_user.getCursor(user_key)) |existing_cursor| { │ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/main_wasm.zig│ ╰─────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │16 │ │17 fn init(json: []const u8, min_height: u32, max_width: u32) !void { │ │18 _ = page_arena.reset(.free_all); │ │19 - // the stored page can borrow a name slice from page_arena (a .user route),│ │20 - // which we just freed — drop it so the next tick's eql never reads it and │ │21 - // always pushes the fresh page's url. │ │19 + // drop the last-pushed page so the next tick pushes the freshly-loaded │ │20 + // page's url. │ │21 last_pushed_page_maybe = null; │ │22 │ │23 // alloc_always so the parsed strings live entirely inside the arena │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │31 session = .{ │ │32 .data = snapshot.session, │ │33 .arena = &page_arena, │ │34 + // one render per page load (init resets the arena), so page-scoped and│ │35 + // session-scoped allocations share the same arena here. │ │36 + .page_arena = &page_arena, │ │37 }; │ │38 │ │39 var next_root = try ui.initRoot(allocator, &snapshot.page, &session); │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ────────╮ │src/serve_ssh.zig│ ╰─────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────╮ │65 .height_cells = if (pty.height_cells == 0) 24 else pty.height_cells, │ │66 }; │ │67 │ │68 - // build the Home page in a session-scoped arena. │ │69 - var page_arena = std.heap.ArenaAllocator.init(allocator); │ │70 - defer page_arena.deinit(); │ │68 + // session-lifetime allocations (login, prefs); Nav owns the per-page arenas. │ │69 + var session_arena = std.heap.ArenaAllocator.init(allocator); │ │70 + defer session_arena.deinit(); │ │71 │ │72 const Repo = rp.Repo(.xit, evt.admin_repo_opts); │ │73 var repo = try Repo.open(io, allocator, .{ .path = handler.admin_repo_path });│ ╰──────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │74 defer repo.deinit(io, allocator); │ │75 - var ui_session = try ui.Session.init(&page_arena, &repo, .{}); │ │76 - │ │77 - const page: ui.Page = try ui.Page.init(&page_arena, ui_session.haxy_moment orelse unreachable, ui_session.data.current_page);│ │75 + var ui_session = try ui.Session.init(&session_arena, &repo, .{}); │ │76 │ │79 - var nav = try ui.Nav.init(allocator, &page, &ui_session); │ │77 + var nav = try ui.Nav.init(allocator, &ui_session); │ │78 defer nav.deinit(allocator); │ │79 │ │80 var session_writer_buf: [8192]u8 = undefined; │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ──╮ │src/try.zig│ ╰───────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │36 │ │37 const cwd_path = try std.process.currentPathAlloc(io, allocator); │ │38 defer allocator.free(cwd_path); │ │39 - │ │40 - var page_arena = std.heap.ArenaAllocator.init(allocator); │ │41 - defer page_arena.deinit(); │ │39 │ │40 const work_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name, "server", "admin" });│ │41 defer allocator.free(work_path); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────╮ │47 try repo.addConfig(io, allocator, .{ .name = "user.name", .value = "haxy" }); │ │48 try repo.addConfig(io, allocator, .{ .name = "user.email", .value = "admin@haxy" });│ │49 │ │53 - var session: ui.Session = undefined; │ │50 + var session_arena = std.heap.ArenaAllocator.init(allocator); │ │51 + defer session_arena.deinit(); │ │52 │ │55 - const page: ui.Page = blk: { │ │53 + var session: ui.Session = blk: { │ │54 var arena = std.heap.ArenaAllocator.init(allocator); │ │55 defer arena.deinit(); │ │56 │ ╰────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │172 // commit the seed events and consume them into the database │ │173 try evt.commitAndConsume(evt.admin_repo_opts, io, allocator, &repo, evt.events_ref, &events_to_consume); │ │174 │ │177 - session = try ui.Session.init(&page_arena, &repo, .{}); │ │178 - break :blk try ui.Page.init(&page_arena, session.haxy_moment orelse unreachable, session.data.current_page);│ │175 + break :blk try ui.Session.init(&session_arena, &repo, .{}); │ │176 }; │ │177 │ │178 // start the server │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────╮ │236 const Runnable = struct { │ │237 io: std.Io, │ │238 allocator: std.mem.Allocator, │ │242 - page: *const ui.Page, │ │239 session: *ui.Session, │ │240 │ │241 pub fn run(self: @This()) !void {│ ╰──────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯