{"id":"coffilhg/namespacesync","name":"namespacesync","scope":"coffilhg","platform":"roblox","description":"This module is a great utility if you need 'singletone' Instances, e.g. your Client and Server modules need a shared folder for their Project state or your custom Plugin should always output in a predictable place.","version":"0.0.0","latest":"0.0.0","versions":["0.0.0"],"license":"MPL-2.0","licenseRating":"caution","licenseCaveats":["File-level copyleft: if you modify this package's own source files, those modified files must be made available under MPL-2.0. Using it unmodified in a closed-source game is fine."],"licenseVerified":false,"dependencies":{"coffilhg/classnametypepairs":{"version":">=0.0.0","alias":"ClassNameTypePairs"},"data-oriented-house/lemonsignal":{"version":"^2.0.0","alias":"LemonSignal"}},"integrity":"47b01bd384253babf60d493f63e03dd26b5589bcb22676b2d79652dbf25839da","likes":0,"downloads":0,"install":"forest install coffilhg/namespacesync","url":"https://forest.dev/p/roblox/coffilhg/namespacesync","files":"https://api.forest.dev/ai/package/roblox/coffilhg/namespacesync/files","readme":"# NamespaceSync\r\n\r\nInspired by **[CoffeeRemotesRefined](<https://github.com/Coffilhg/Useful-Modules/tree/CoffeeRemotesRefined>)**, where similar approach was first invented and used.\r\n\r\nThis module is a great utility if you need \"singletone\" Instances, e.g. your Client and Server modules need a shared folder for their Project state or your custom Plugin should always output in a predictable place.\r\n\r\nThis module will take care of this! **[Read below...](#basic-usage)**\r\n\r\n\r\n\r\n## Available Here!\r\n- **[This repository](src/init.luau) ~ [src/init.luau](src/init.luau)**\r\n- **[Wally](<https://wally.run/package/coffilhg/namespacesync>)**\r\n\r\n    ```toml\r\n    NamespaceSync = \"coffilhg/namespacesync@0.0.0\"\r\n    ```\r\n- **[Rotriever](<https://github.com/Coffilhg/Useful-Modules/releases/tag/vNamespaceSync/0.0.0>)**\r\n\r\n    ```toml\r\n    NamespaceSync = \"github.com/Coffilhg/Useful-Modules@NamespaceSync/0.0.0\"\r\n    ```\r\n\r\n<!-- **[Creator Store](<https://create.roblox.com/store/category/gameplay?creatorName=coffilhg>)** ~ **[NamespaceSync](<https://create.roblox.com/store/asset/123456789/NamespaceSync>)**-->\r\n\r\n---\r\n\r\n## Basic Usage\r\n\r\n### Require the module\r\n> all uses of `NamespaceSync` in code examples below refer to this\r\n```luau\r\nconst NamespaceSync = require(`@game/ReplicatedStorage/Packages/NamespaceSync`)\r\n```\r\n\r\n### Use the module\r\nProvided a name and project version string, it will find an existing or create a new Folder (or instance of a given ClassName) with the following:\r\n- Name = input name\r\n- ClassName = Folder or whichever was input\r\n- Tag = `{name}_{projectVersion}`\r\n- Attribute `{name}V` = `{name}_{projectVersion}`\r\n> The attribute name will be made safe automatically to comply with [these Limits](<https://create.roblox.com/docs/en-us/reference/engine/classes/Instance#SetAttribute>)\r\n\r\nThis describes the initial idea this served, on server-side you'd do\r\n```lua\r\n-- making a Folder\r\nconst MainFolder = NamespaceSync:mkdir(\r\n    \"1.2.3\", -- projectVersion\r\n\t\"ReplicationService\", -- name\r\n\t-- where: Instance? -- this is where to parent if there was no ReplicationService Folder with matching metadata; defaults to ReplicatedStorage\r\n\t-- isRecursive: boolean?, -- this is whether we should search all DESCENDANTS (:GetDescendants) of where, defaults to false and searches onle the direct children (:GetChildren)\r\n\t-- debugPrefix: (string | any)? -- every warning emitted by the module starts with `{debugPrefix} `\r\n)\r\n```\r\nand then on client-side you'd indefinitely await for the folder until server creates it\r\n```lua\r\n-- awaiting a Folder\r\nconst MainFolder = NamespaceSync:cd(\r\n    \"1.2.3\", -- projectVersion\r\n\t\"ReplicationService\", -- name\r\n\t-- where: Instance? -- same as above\r\n\t-- isRecursive: boolean?, -- same as above + it also determines `:FindFirstX` and `.XAdded:Connect` usage. The point is the same: if isRecursive - search and await a matching descendant of where, otherwise (false or default) - search and await a matching child of where\r\n\t-- debugPrefix: (string | any)? -- same as above\r\n    -- yieldWarningTime: number? -- imagine you made a typo somewhere and now it silently yields (waits) indefinitely (forever),\r\n    -- yieldWarningTime got you covered, if nothing is found in yieldWarningTime seconds, a warning is emitted, defaults to 15\r\n)\r\n```\r\nnow parent any instances inside, you can be almost certain this never overlaps with modules or projects of other developers and different versions of your own module/project. This is especially good if dependencies are intentionally not deduplicated, but use this, achieving foolproof isolation.\r\n\r\nAnd maybe you don't want a **Folder**, maybe you want a **Model** or an **ArcHandles** for whichever reason, sure, anything that **Instance.new** supports, just use\r\n```lua\r\n-- making your whatever ClassName\r\nconst MainWhatever = NamespaceSync:GetOrCreate(\r\n    className, -- any class name supported by Instance.new\r\n    -- everything else as in :mkdir above, i.e.\r\n    projectVersion, -- obligatory, same as above\r\n    name, -- obligatory, same as above\r\n    where, -- optional, same as above\r\n    isRecursive, -- optional, same as above\r\n    debugPrefix -- optional, same as above\r\n)\r\n```\r\nand in a different script\r\n```lua\r\n-- awaiting for your whatever ClassName\r\nconst MainWhatever = NamespaceSync:Await(\r\n    className, -- value .ClassName property of the object you created using :GetOrCreate\r\n    -- everything else as in :cd above, i.e.\r\n    projectVersion, -- obligatory, same as above\r\n    name, -- obligatory, same as above\r\n    where, -- optional, same as above\r\n    isRecursive, -- optional, same as above\r\n    debugPrefix, -- optional, same as above\r\n    yieldWarningTime -- optional, same as above\r\n)\r\n```\r\n\r\nSo you end up with name + ClassName + a tag + a specific attribute name with a specfic value\r\n\r\nSuch combination makes it quite unique, but if that's not enough or too much (e.g. you only want the name + ClassName without tag & attribute metadata), this module still has you covered:\r\n\r\n### Use it more\r\n\r\nGetOrCreateManual always validates for name + ClassName.\r\n\r\nYou can set custom modifiers or keep no modifiers - you only have name + ClassName, nothing else.\r\n\r\n```lua\r\nconst YouNameIt = NamespaceSync:GetOrCreateManual(\r\n    className,\r\n    name,\r\n    where,\r\n    modifiers,\r\n    isRecursive,\r\n    debugPrefix\r\n)\r\n```\r\n\r\n```lua\r\nconst YouNameIt = NamespaceSync:AwaitManual(\r\n    className,\r\n    name,\r\n    where,\r\n    modifiers,\r\n    isRecursive,\r\n    debugPrefix,\r\n    yieldWarningTime\r\n)\r\n```\r\n\r\n---\r\n\r\n## To-Do\r\n\r\n- [ ] Expand the README\r\n\r\n---\r\n\r\n## DEPENDENCIES\r\n\r\n- [ClassNameTypePairs](<https://github.com/Coffilhg/ClassNameTypePairs>)\r\n- [LemonSignal](<https://github.com/Data-Oriented-House/LemonSignal>)\r\n\r\n---\r\n\r\n## License & Attribution\r\n\r\nThis module is licensed under the **Mozilla Public License 2.0 (MPL-2.0)**.\r\n\r\n#### What this means for Roblox Developers:\r\n* **Use & Modify:** You can freely use this module in any public, private, or commercial Roblox game.\r\n* **File-Level Copyleft:** If you modify the source code of this module itself, you must make your modified version of the module publicly available under the MPL 2.0.\r\n* **No Viral Code Leakage:** Including this module in your game does **not** force you to open-source your other game scripts, UI layouts, or proprietary codebase. \r\n\r\nSee the full terms in the [LICENSE](LICENSE) file.\r\n\r\nAttribution to all dependencies is included in [Notice](NOTICE)\r\n\r\nCopyright © 2026 @Coffilhg (Roblox UserId 517222346)","readmeTruncated":false}