-module(shelf). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/shelf.gleam"). -export([config/3, write_mode/2, get_name/1, get_path/1, get_base_directory/1, get_write_mode/1, validate_path/2]). -export_type([shelf_error/0, write_mode/0, config/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type shelf_error() :: not_found | key_already_present | table_closed | not_owner | {file_error, binary()} | name_conflict | {invalid_path, binary()} | file_size_limit_exceeded | {type_mismatch, list(gleam@dynamic@decode:decode_error())} | {erlang_error, binary()}. -type write_mode() :: write_back | write_through. -opaque config() :: {config, binary(), binary(), binary(), write_mode()}. -file("src/shelf.gleam", 148). ?DOC( " Create a config with defaults (WriteBack mode).\n" "\n" " The `name` is a diagnostic label for the table — it is not used as an\n" " ETS table name and does not need to be unique. Multiple tables can\n" " share the same name as long as they use different DETS file paths.\n" "\n" " The `base_directory` restricts DETS file paths to prevent directory\n" " traversal attacks. The `path` is resolved relative to `base_directory`.\n" "\n" " ```gleam\n" " let conf = shelf.config(name: \"users\", path: \"users.dets\",\n" " base_directory: \"/app/data\")\n" " ```\n" ). -spec config(binary(), binary(), binary()) -> config(). config(Name, Path, Base_directory) -> {config, Name, Path, Base_directory, write_back}. -file("src/shelf.gleam", 165). ?DOC( " Set the write mode on a config.\n" "\n" " ```gleam\n" " let conf =\n" " shelf.config(name: \"users\", path: \"users.dets\",\n" " base_directory: \"/app/data\")\n" " |> shelf.write_mode(shelf.WriteThrough)\n" " ```\n" ). -spec write_mode(config(), write_mode()) -> config(). write_mode(Config, Mode) -> {config, erlang:element(2, Config), erlang:element(3, Config), erlang:element(4, Config), Mode}. -file("src/shelf.gleam", 173). ?DOC(false). -spec get_name(config()) -> binary(). get_name(Config) -> erlang:element(2, Config). -file("src/shelf.gleam", 178). ?DOC(false). -spec get_path(config()) -> binary(). get_path(Config) -> erlang:element(3, Config). -file("src/shelf.gleam", 183). ?DOC(false). -spec get_base_directory(config()) -> binary(). get_base_directory(Config) -> erlang:element(4, Config). -file("src/shelf.gleam", 188). ?DOC(false). -spec get_write_mode(config()) -> write_mode(). get_write_mode(Config) -> erlang:element(5, Config). -file("src/shelf.gleam", 197). ?DOC(false). -spec validate_path(binary(), binary()) -> {ok, binary()} | {error, shelf_error()}. validate_path(Path, Base_directory) -> case gleam_stdlib:contains_string(Path, <<"\x{0}"/utf8>>) of true -> {error, {invalid_path, <<"Path contains null bytes"/utf8>>}}; false -> case gleam_stdlib:contains_string(Base_directory, <<"\x{0}"/utf8>>) of true -> {error, {invalid_path, <<"Base directory contains null bytes"/utf8>>}}; false -> shelf_ffi:validate_path(Path, Base_directory) end end.