{"id":"justethecoder/sharp","name":"sharp","scope":"justethecoder","platform":"roblox","description":"Mirrored from the Wally registry.","version":"1.1.2","latest":"1.1.2","versions":["0.1.1","0.1.2","1.1.1","1.1.2"],"license":"MIT","licenseRating":"safe","licenseCaveats":["License identified from the packaged LICENSE file; the manifest declared none."],"licenseVerified":true,"dependencies":{},"integrity":"8b9a1b0ac26bcc19efe986c172bbb37d878316ea532916006bf2d2509cbe375a","likes":0,"downloads":0,"install":"forest install justethecoder/sharp","url":"https://forest.dev/p/roblox/justethecoder/sharp","files":"https://api.forest.dev/ai/package/roblox/justethecoder/sharp/files","readme":"<div align=\"center\">\n\t<h1>Sharp</h1>\n\t<p>A powerful framework for networking and organization.</p>\n</div>\n\n## Initialization\n\n```lua\n    local ReplicatedStorage = game:GetService(\"ReplicatedStorage\")\n    local Sharp = require(ReplicatedStorage:WaitForChild(\"Sharp\"))\n\n    Sharp.onStart(function()\n        print(\"Sharp is ready!\")\n    end)\n\n    task.spawn(function()\n        Sharp.await() -- Yield until Sharp is ready.\n    end)\n\n    Sharp.start() -- Yields if necessary\n```\n\nAfter initialization, Sharp can be accessed through the `Sharp` global variable.\n\n## Adding libraries and singletons\n\nYou can add folders containing modules as either libraries or singletons.\nThis must be done before initialization.\n\n```lua\n    Sharp.addLibraries(ReplicatedStorage.Source.Libraries)\n    Sharp.addSingletons(ReplicatedStorage.Source.Singletons)\n```\n\n## Libraries\n\nLibraries are modules which are lazy loaded when needed.\nThey can be accessed after initialization through the `Sharp.Library` table.\n\n```lua\n    local Signal = Sharp.Library.Signal\n    local Promise = Sharp.Library.Promise\n```\n\n## Singletons\n\nSingletons are the core of Sharp. They are a way to create a single instance of a class that can be accessed from anywhere in the code.\n\nAccessing singletons:\n\n```lua\n    local MySingleton = Sharp.Singleton.MySingleton\n```\n\nCreating singletons:\n\n```lua\n    local MySingleton = Sharp.Singleton.define(\"MySingleton\")\n    MySingleton.someValue = \"Hello!\"\n```\n\nor\n\n```lua\n    local MySingleton = Sharp.Singleton.define(\"MySingleton\", {\n        someValue = \"Hello!\"\n    })\n```\n\nSingletons can be accessed before they are created, and the optional data will be merged\nwith the existing definition allowing cross-referencing singletons:\n\n```lua\n\t-- Singleton 1\n\tlocal MySingleton1 = Sharp.Singleton.MySingleton1\n\n\tlocal MySingleton2 = Sharp.Singleton.define(\"MySingleton2\")\n\n\t-- Singleton 2\n\tlocal MySingleton2 = Sharp.Singleton.MySingleton2\n\n\tlocal MySingleton1 = Sharp.Singleton.define(\"MySingleton1\")\n```\n\nSingletons also contain optional lifecycle methods.\nThese methods are available to all modules inside a singleton folder not just ones\nwhich utilize the Singleton library.\n\n```lua\n    function MySingleton.first()\n    end\n\n    -- The on function is called only after all first methods have been called.\n    function MySingleton.on()\n    end\n```\n\n## Packages\n\nPackages are a way to access sub-modules of singletons and libraries.\nAlso lazy loaded.\n\n```lua\n    local MyPackage = Sharp.Package.MyPackage\n    local MySubModule = MyPackage.SubModule\n```\n\n## Networking\n\nSharp also offers some powerful networking features through its\nbuilt-in Net library.\n\n### Networking basics\n\nNet has two types of events:\nEvent - Your standard event; can be fired and listened to.\nAsyncEvent - An event that only be fired on the client and returns values asynchronously through a promise.\n\nServer-side example:\n\n```lua\n    local Net = Sharp.Library.Net\n\n    local MyBridge = Net.now(\"MyBridge\", {\n        myEvent = Net.Type.event(),\n        myAsyncEvent = Net.Type.asyncEvent()\n    })\n\n    MyBridge.myEvent:Connect(function(client, message)\n        print(\"Client \" .. client.Name .. \" fired myEvent with message \" .. message)\n        --> \"Client client fired myEvent with message Hello World!\"\n    end)\n\n    MyBridge.myAsyncEvent:setCallback(function(client, ...)\n        task.wait(5)\n        return \"Hello \" .. client.Name .. \"from server!\"\n    end)\n\n    MyBridge.myEvent:sendToClient(Players.SomePlayer1, \"Hello World!\")\n    MyBridge.myEvent:sendToClients({Players.SomePlayer1, Players.SomePlayer2}, \"Hello World!\")\n    MyBridge.myEvent:sendToClientsExcept({Players.SomePlayer1, Players.SomePlayer2}, \"Hello World!\")\n    MyBridge.myEvent:sendToAllClients(\"Hello World!\")\n```\n\nClient-side example:\n\n```lua\n    local Net = Sharp.Library.Net\n\n     -- On the client you can use Net.Trove to automatically get all events from the server.\n    local MyBridge = Net.now(\"MyBridge\", Net.Trove)\n\n    MyBridge.myEvent:Connect(function(message)\n        print(message) --> \"Hello World!\"\n    end)\n\n    MyBridge.myAsyncEvent:setTimeot(3) --> If the callback takes longer than 3 seconds, it will be aborted.\n\n    MyBridge.myEvent:sendToServer(\"Hello World!\")\n    local status, message = MyBridge.myAsyncEvent:callServer():await()\n    --> promise failed since call took longer than 3 seconds\n```\n\n### Using middleware\n\nSharp also offers a middleware system for networking.\nThere are two types of middleware:\nInbound - Called when an event is received\nOutbound - Called when an event is sent\n\nServer-side example:\n\n```lua\n    local MyBridge = ...\n\n    MyBridge.myEvent:useInboundMiddleware({\n        -- Limit the number of call to 10 per minute.\n        Net.Middleware.throttle(10),\n        -- Check if the first argument is a string.\n        -- Usage with t highly recommended.\n        Net.Middleware.typeCheck(function(argument)\n            return type(argument) == \"string\"\n        end)\n    })\n\n    MyBridge.myEvent:useOutboundMiddleware({\n        -- Only calls the event on clients with names\n        -- that are longer than 5 characters.\n        Net.Middleware.block(function(client, ...)\n            return client.Name:len() > 5\n        end)\n    })\n```\n\nMiddleware only allows for cancelling an event call.\nTo modify the arguments use :outboundProcess() and :inboundProcess() which both\naccept a function that takes the arguments and returns the modified arguments.\nThese are called after the middleware has been processed.\n\nClient and server:\n\n```lua\n    local MyBridge = ...\n\n    local function serialize(...)\n        local args = table.pack(...)\n        -- serialize\n        return table.unpack(args, 1, args.n)\n    end\n\n    local function deserialize(...)\n        local args = table.pack(...)\n        -- deserialize\n        return table.unpack(args, 1, args.n)\n    end\n\n    MyBridge.myEvent:inboundProcess(deserialize)\n    MyBridge.myEvent:outboundProcess(serialize)\n```\n\nAre you noticing what I'm noticing?\nWhat if we want to do more than just serialize and deserialize?\nI want to have multiple functions that do different things.\nIn this case you can use Net.chain(...) to do just that.\n\n```lua\n    local MyBridge = ...\n\n    local function deserialize(...)\n        local args = table.pack(...)\n        -- deserialize\n        return table.unpack(args, 1, args.n)\n    end\n\n    local function clampNumber(number)\n        return math.clamp(number, 0, 100)\n    end\n\n    MyBridge.myEvent:inboundProcess(Net.chain(\n    \tdeserialize, clampNumber\n    ))\n    -- Net does this automatically if you pass in\n    -- more than one function.\n    MyBridge.myEvent:inboundProcess(deserialize, clampNumber)\n```\n\n### With singletons\n\nOn top of the Net.one constructor, Net offers two other constructors:\nNet.use - Accepts an optional table as the second argument.\nNet.with - Same as Net.use, but constructs a singleton.\n\n```lua\n    local MyNetObject = Net.use(\"MyNetObject\", {\n        value = \"Hello!\"\n    })\n\n    -- Again, Net.Trove can be used on the client.\n    MyNetObject:netAdd({\n        myEvent = Net.Type.event(),\n        myAsyncEvent = Net.Type.asyncEvent()\n    })\n\n    -- Events are added to the table.\n    MyNetObject.myEvent:Connect(function(message)\n        print(message)\n    end)\n```\n\nWith Singletons:\n\n```lua\n    -- This doesn't look very nice.\n    local MyNetObject = Net.use(\"MyNetObject\", Sharp.Singleton.define(\"MyNetObject\", {\n        value = \"Hello!\"\n    }))\n\n    -- Instead use Net.with\n    local MyNetObject = Net.with(\"MyNetObject\", {\n        value = \"Hello!\"\n    })\n\n    -- Again, Net.Trove can be used on the client.\n    MyNetObject:netAdd({\n        myEvent = Net.Type.event(),\n        myAsyncEvent = Net.Type.asyncEvent()\n    })\n\n    -- Events are added to the table.\n    MyNetObject.myEvent:Connect(function(message)\n        print(message)\n    end)\n```\n","readmeTruncated":false}