@rbxts/zyntex-sdk 1.0.2 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 delucted
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 delucted
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,8 +1,6 @@
1
- # zyntex-sdk
2
- The Roblox Zyntex SDK.
3
-
4
- Types may not be complete, I am adding them as I use them.
5
-
6
- # Download
7
- To download the SDK, please follow the instructions in the Zyntex documentation:
8
- https://docs.zyntex.dev/download
1
+ # zyntex-sdk
2
+ The Roblox Zyntex SDK.
3
+
4
+ # Download
5
+ To download the SDK, please follow the instructions in the Zyntex documentation:
6
+ https://docs.zyntex.dev/download
package/package.json CHANGED
@@ -1,11 +1,29 @@
1
- {
2
- "name": "@rbxts/zyntex-sdk",
3
- "version": "1.0.2",
4
- "description": "Typescript types for: The Roblox Zyntex SDK.",
5
- "main": "init.lua",
6
- "license": "MIT",
7
- "types": "index.d.ts",
8
- "publishConfig": {
9
- "access": "public"
10
- }
11
- }
1
+ {
2
+ "name": "@rbxts/zyntex-sdk",
3
+ "version": "6.0.0",
4
+ "description": "Typescript types for: The Roblox Zyntex SDK.",
5
+ "main": "src/init.lua",
6
+ "scripts": {
7
+ "build": "rbxtsc",
8
+ "watch": "rbxtsc -w"
9
+ },
10
+ "keywords": [],
11
+ "license": "MIT",
12
+ "types": "src/index.d.ts",
13
+ "files": [
14
+ "src"
15
+ ],
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "devDependencies": {
20
+ "@rbxts/compiler-types": "^3.0.0-types.0",
21
+ "@rbxts/types": "^1.0.867",
22
+ "@typescript-eslint/eslint-plugin": "^8.38.0",
23
+ "@typescript-eslint/parser": "^8.38.0",
24
+ "eslint": "^9.32.0",
25
+ "eslint-plugin-roblox-ts": "^1.0.0",
26
+ "roblox-ts": "^3.0.0",
27
+ "typescript": "^5.8.3"
28
+ }
29
+ }
@@ -0,0 +1,114 @@
1
+ local Session = require(script.Parent:WaitForChild("api"))
2
+
3
+ local Experiment = {}
4
+ Experiment.__index = Experiment
5
+
6
+ -- Represents an experiment instance
7
+ type ExperimentType = {
8
+ id: string; -- The unique ID of the experiment (e.g., "new_shop_ui").
9
+ _session: Session.Session; -- Reference to the main Zyntex session.
10
+ }
11
+
12
+ export type Experiment = typeof(setmetatable({} :: ExperimentType, Experiment))
13
+
14
+ local Group = {}
15
+ Group.__index = Group
16
+
17
+ -- Represents a group instance
18
+ type GroupType = {
19
+ id: string; -- The unique ID of the group (e.g., "group_a").
20
+ playerId: number; -- The ID of the player that is in this group
21
+ _experiment: Experiment;
22
+ }
23
+
24
+ export type Group = typeof(setmetatable({} :: GroupType, Group))
25
+
26
+ --[[
27
+ @function Group:Convert
28
+ @description Registers a conversion for that player in the group.
29
+ @param value number? -- The value this conversion provided. For example: total robux spent, time spent completing tutorial
30
+ ]]
31
+ function Group.Convert(self: Group, value: number?)
32
+ self._experiment._session:post(`/experiments/{self._experiment.id}`, {
33
+ value = value or 0;
34
+ group_id = self.id;
35
+ player_id = self.playerId;
36
+ },
37
+ true
38
+ )
39
+ end
40
+
41
+ --[[
42
+ @constructor Group.new
43
+ @description Constructs a new Group object.
44
+ @param session Session -- Reference to the main client (for API calls).
45
+ @param id string -- Group ID as defined in the dashboard.
46
+ @return Group
47
+ ]]
48
+ function Group.new(Experiment: Experiment, id: string, playerId: number)
49
+ local self = {}
50
+ self.id = id
51
+ self.playerId = playerId
52
+ self._experiment = Experiment
53
+
54
+ return setmetatable(self, Group)
55
+ end
56
+
57
+ --[[
58
+ @constructor Experiment.new
59
+ @description Constructs a new Experiment object.
60
+ @param session Session -- Reference to the main client (for API calls).
61
+ @param id string -- Experiment ID as defined in the dashboard.
62
+ @return Experiment
63
+ ]]
64
+ function Experiment.new(session: Session.Session, id: string): Experiment?
65
+ local self = {}
66
+ self._session = session
67
+ self.id = id
68
+
69
+ local manifest = session:get(`/experiments/{id}/manifest`)
70
+
71
+ if not manifest.success then
72
+ if manifest.statusCode == 404 then
73
+ return nil
74
+ end
75
+
76
+ error(`Error when fetching experiment {id}: {manifest.user_message}`)
77
+ end
78
+
79
+ return setmetatable(self, Experiment)
80
+ end
81
+
82
+ --[[
83
+ @function GetStatus
84
+ @description Fetches the current status of the experiment.
85
+ @return Experiment
86
+ ]]
87
+ function Experiment.GetStatus(self: Experiment): "active" | "paused" | "archived"
88
+ local res = self._session:get(`/experiments/{self.id}/manifest`)
89
+
90
+ if not res.succeess then
91
+ error(`Failure when fetching experiment {self.id} status: {res.user_message}`)
92
+ end
93
+
94
+ return res.data.status
95
+ end
96
+
97
+ --[[
98
+ @function GetGroup
99
+ @description Registers an entry and server assigns player a group.
100
+ @param playerId Player | number -- The Player to register, as a Player object or number (userId)
101
+ @return string
102
+ ]]
103
+ function Experiment.GetGroup(self: Experiment, player: Player | number): Group
104
+ local playerId = if type(player) == "number" then player else player.UserId
105
+ local res = self._session:get(`/experiments/{self.id}/group/{playerId}`)
106
+
107
+ if not res.success then
108
+ error(`Failure fetching group for player {playerId}: {res.user_message}`)
109
+ end
110
+
111
+ return Group.new(self, res.data, playerId)
112
+ end
113
+
114
+ return Experiment
@@ -0,0 +1,23 @@
1
+ local Zyntex = require(script:FindFirstChild("Zyntex"))
2
+ local Session = require(script:FindFirstChild("api"))
3
+
4
+ return setmetatable({}, {
5
+ --[[
6
+ Gets the current version of this module.
7
+ ]]
8
+ __index = function(self, index)
9
+ if string.lower(index) == "version" then
10
+ return Zyntex.VERSION
11
+ end
12
+ if string.lower(index) == "isZyntex" then --// Important for the Zyntex upgrader plugin. When it searches for the module, make sure it has this.
13
+ return true
14
+ end
15
+ end,
16
+ --[[
17
+ Returns a new Zyntex object.
18
+ https://docs.zyntex.dev
19
+ ]]
20
+ __call = function(self, gameToken: string): Zyntex.Zyntex
21
+ return Zyntex.new(gameToken)
22
+ end,
23
+ })
@@ -1,176 +1,176 @@
1
- local Session = require(script.Parent:WaitForChild("api"))
2
- local HttpService = game:GetService("HttpService")
3
-
4
- local Telemetry = {}
5
- Telemetry.__index = Telemetry
6
-
7
- export type LabelSet = { [string]: string }
8
-
9
- export type MetricOpts = {
10
- --[[
11
- Optional human-readable description
12
- ]]
13
- description: string?,
14
- --[[
15
- Labels, used for filtering metrics on the dashboard
16
- ]]
17
- labels: { string }?,
18
- --[[
19
- Only for Histogram
20
- ]]
21
- buckets: { number }?,
22
- }
23
-
24
- export type CounterMetric = {
25
- inc: (self: CounterMetric, delta: number?, labels: LabelSet?) -> (),
26
- }
27
-
28
- export type GaugeMetric = {
29
- set: (self: GaugeMetric, value: number, labels: LabelSet?) -> (),
30
- inc: (self: GaugeMetric, delta: number?, labels: LabelSet?) -> (),
31
- dec: (self: GaugeMetric, delta: number?, labels: LabelSet?) -> (),
32
- }
33
-
34
- export type HistogramMetric = {
35
- observe: (self: HistogramMetric, value: number, labels: LabelSet?) -> (),
36
- }
37
-
38
- export type SummaryMetric = {
39
- observe: (self: SummaryMetric, value: number, labels: LabelSet?) -> (),
40
- }
41
-
42
- function Telemetry.new(registryName: string?, flushEvery: number?, session: Session.Session)
43
- return setmetatable({
44
- _name = registryName or "default",
45
- _buffer = {}, -- pending samples
46
- _flushEvery = flushEvery or 10,
47
- _lastFlush = os.clock(),
48
- _session = session
49
- }, Telemetry)
50
- end
51
-
52
- --[[
53
- Generic pushSample shared by all metric types
54
- ]]
55
- local function pushSample(self, kind: string, name: string, value, labels: LabelSet)
56
- table.insert(self._buffer, {
57
- t = os.time(), -- UTC seconds
58
- k = kind, -- counter | gauge | hist | sum
59
- n = name, -- metric name
60
- v = value, -- number or bucket-map
61
- l = labels -- table<string,string>
62
- })
63
-
64
- if os.clock() - self._lastFlush >= self._flushEvery then
65
- self:flush()
66
- end
67
- end
68
-
69
- function Telemetry:flush()
70
- if #self._buffer == 0 then return end
71
- pcall(function()
72
- self._session:post(
73
- "/telemetry/push",
74
- {buffer = self._buffer}
75
- )
76
- end)
77
- self._buffer, self._lastFlush = {}, os.clock()
78
- end
79
-
80
- --[[
81
- Creates (or fetches) a monotonically increasing **counter** metric.
82
-
83
- @param self Telemetry – the registry instance.
84
- @param name string – metric name (snake_case).
85
- @param opts MetricOpts? – optional descriptor & label schema.
86
-
87
- @return CounterMetric handle – call `:inc()` to push samples.
88
-
89
- Example
90
- ```lua
91
- local shots = registry:Counter("weapon_shots_total", {
92
- description = "Number of shots fired per weapon",
93
- labels = {"weapon"}
94
- })
95
-
96
- shots:inc() -- +1
97
- shots:inc(3, {weapon="AK-47"}) -- +3 with a label
98
- ```
99
- ]]--
100
- function Telemetry:Counter(name: string, opts: MetricOpts?): CounterMetric
101
- local total = 0
102
- return ({
103
- inc = function(_: CounterMetric, delta: number?, lbls: LabelSet?)
104
- total += delta or 1
105
- pushSample(self, "counter", name, total, lbls or {})
106
- end,
107
- } :: any) :: CounterMetric
108
- end
109
-
110
- --[[
111
- Creates a **gauge** metric – an instantaneous value that can go up
112
- or down (e.g. memory, player count, FPS).
113
-
114
- `set()` overrides the value directly, while `inc()` / `dec()` apply
115
- deltas.
116
-
117
- @return GaugeMetric handle.
118
- ]]--
119
- function Telemetry:Gauge(name: string, opts: MetricOpts?): GaugeMetric
120
- return ({
121
-
122
- set = function(_: GaugeMetric, value: number, lbls: LabelSet?)
123
- pushSample(self, "gauge", name, value, lbls or {})
124
- end,
125
-
126
- inc = function(_: GaugeMetric, delta: number?, lbls: LabelSet?)
127
- pushSample(self, "gauge", name, delta or 1, lbls or {})
128
- end,
129
-
130
- dec = function(_: GaugeMetric, delta: number?, lbls: LabelSet?)
131
- pushSample(self, "gauge", name, -(delta or 1), lbls or {})
132
- end,
133
-
134
- } :: any) :: GaugeMetric
135
- end
136
-
137
- --[[
138
- Creates a **histogram** metric – captures a distribution of values
139
- (e.g. damage dealt, ping). `buckets` may be provided in `opts`.
140
-
141
- The raw sample value is sent unchanged; bucketing happens on the
142
- back-end so bucket definitions can evolve without client updates.
143
-
144
- @return HistogramMetric handle.
145
- ]]--
146
- function Telemetry:Histogram(name: string, opts: MetricOpts?): HistogramMetric
147
- local buckets: {number}? = opts and opts.buckets
148
- return ({
149
-
150
- observe = function(_: HistogramMetric, value: number, lbls: LabelSet?)
151
- local combined: LabelSet = lbls and table.clone(lbls) or {}
152
- if buckets then combined._buckets = HttpService:JSONEncode(buckets) end
153
- pushSample(self, "hist", name, value, combined)
154
- end,
155
-
156
- } :: any) :: HistogramMetric
157
- end
158
-
159
- --[[
160
- Creates a **summary** metric – similar to histogram but intended
161
- for quantile estimation (P-style summaries). Uses a single `observe`
162
- method.
163
-
164
- @return SummaryMetric handle.
165
- ]]--
166
- function Telemetry:Summary(name: string, opts: MetricOpts?): SummaryMetric
167
- return ({
168
-
169
- observe = function(_: SummaryMetric, value: number, lbls: LabelSet?)
170
- pushSample(self, "sum", name, value, lbls or {})
171
- end,
172
-
173
- } :: any) :: SummaryMetric
174
- end
175
-
176
- return Telemetry
1
+ local Session = require(script.Parent:WaitForChild("api"))
2
+ local HttpService = game:GetService("HttpService")
3
+
4
+ local Telemetry = {}
5
+ Telemetry.__index = Telemetry
6
+
7
+ export type LabelSet = { [string]: string }
8
+
9
+ export type MetricOpts = {
10
+ --[[
11
+ Optional human-readable description
12
+ ]]
13
+ description: string?,
14
+ --[[
15
+ Labels, used for filtering metrics on the dashboard
16
+ ]]
17
+ labels: { string }?,
18
+ --[[
19
+ Only for Histogram
20
+ ]]
21
+ buckets: { number }?,
22
+ }
23
+
24
+ export type CounterMetric = {
25
+ inc: (self: CounterMetric, delta: number?, labels: LabelSet?) -> (),
26
+ }
27
+
28
+ export type GaugeMetric = {
29
+ set: (self: GaugeMetric, value: number, labels: LabelSet?) -> (),
30
+ inc: (self: GaugeMetric, delta: number?, labels: LabelSet?) -> (),
31
+ dec: (self: GaugeMetric, delta: number?, labels: LabelSet?) -> (),
32
+ }
33
+
34
+ export type HistogramMetric = {
35
+ observe: (self: HistogramMetric, value: number, labels: LabelSet?) -> (),
36
+ }
37
+
38
+ export type SummaryMetric = {
39
+ observe: (self: SummaryMetric, value: number, labels: LabelSet?) -> (),
40
+ }
41
+
42
+ function Telemetry.new(registryName: string?, flushEvery: number?, session: Session.Session)
43
+ return setmetatable({
44
+ _name = registryName or "default",
45
+ _buffer = {}, -- pending samples
46
+ _flushEvery = flushEvery or 10,
47
+ _lastFlush = os.clock(),
48
+ _session = session
49
+ }, Telemetry)
50
+ end
51
+
52
+ --[[
53
+ Generic pushSample shared by all metric types
54
+ ]]
55
+ local function pushSample(self, kind: string, name: string, value, labels: LabelSet)
56
+ table.insert(self._buffer, {
57
+ t = os.time(), -- UTC seconds
58
+ k = kind, -- counter | gauge | hist | sum
59
+ n = name, -- metric name
60
+ v = value, -- number or bucket-map
61
+ l = labels -- table<string,string>
62
+ })
63
+
64
+ if os.clock() - self._lastFlush >= self._flushEvery then
65
+ self:flush()
66
+ end
67
+ end
68
+
69
+ function Telemetry:flush()
70
+ if #self._buffer == 0 then return end
71
+ pcall(function()
72
+ self._session:post(
73
+ "/telemetry/push",
74
+ {buffer = self._buffer}
75
+ )
76
+ end)
77
+ self._buffer, self._lastFlush = {}, os.clock()
78
+ end
79
+
80
+ --[[
81
+ Creates (or fetches) a monotonically increasing **counter** metric.
82
+
83
+ @param self Telemetry – the registry instance.
84
+ @param name string – metric name (snake_case).
85
+ @param opts MetricOpts? – optional descriptor & label schema.
86
+
87
+ @return CounterMetric handle – call `:inc()` to push samples.
88
+
89
+ Example
90
+ ```lua
91
+ local shots = registry:Counter("weapon_shots_total", {
92
+ description = "Number of shots fired per weapon",
93
+ labels = {"weapon"}
94
+ })
95
+
96
+ shots:inc() -- +1
97
+ shots:inc(3, {weapon="AK-47"}) -- +3 with a label
98
+ ```
99
+ ]]--
100
+ function Telemetry:Counter(name: string, opts: MetricOpts?): CounterMetric
101
+ local total = 0
102
+ return ({
103
+ inc = function(_: CounterMetric, delta: number?, lbls: LabelSet?)
104
+ total += delta or 1
105
+ pushSample(self, "counter", name, total, lbls or {})
106
+ end,
107
+ } :: any) :: CounterMetric
108
+ end
109
+
110
+ --[[
111
+ Creates a **gauge** metric – an instantaneous value that can go up
112
+ or down (e.g. memory, player count, FPS).
113
+
114
+ `set()` overrides the value directly, while `inc()` / `dec()` apply
115
+ deltas.
116
+
117
+ @return GaugeMetric handle.
118
+ ]]--
119
+ function Telemetry:Gauge(name: string, opts: MetricOpts?): GaugeMetric
120
+ return ({
121
+
122
+ set = function(_: GaugeMetric, value: number, lbls: LabelSet?)
123
+ pushSample(self, "gauge", name, value, lbls or {})
124
+ end,
125
+
126
+ inc = function(_: GaugeMetric, delta: number?, lbls: LabelSet?)
127
+ pushSample(self, "gauge", name, delta or 1, lbls or {})
128
+ end,
129
+
130
+ dec = function(_: GaugeMetric, delta: number?, lbls: LabelSet?)
131
+ pushSample(self, "gauge", name, -(delta or 1), lbls or {})
132
+ end,
133
+
134
+ } :: any) :: GaugeMetric
135
+ end
136
+
137
+ --[[
138
+ Creates a **histogram** metric – captures a distribution of values
139
+ (e.g. damage dealt, ping). `buckets` may be provided in `opts`.
140
+
141
+ The raw sample value is sent unchanged; bucketing happens on the
142
+ back-end so bucket definitions can evolve without client updates.
143
+
144
+ @return HistogramMetric handle.
145
+ ]]--
146
+ function Telemetry:Histogram(name: string, opts: MetricOpts?): HistogramMetric
147
+ local buckets: {number}? = opts and opts.buckets
148
+ return ({
149
+
150
+ observe = function(_: HistogramMetric, value: number, lbls: LabelSet?)
151
+ local combined: LabelSet = lbls and table.clone(lbls) or {}
152
+ if buckets then combined._buckets = HttpService:JSONEncode(buckets) end
153
+ pushSample(self, "hist", name, value, combined)
154
+ end,
155
+
156
+ } :: any) :: HistogramMetric
157
+ end
158
+
159
+ --[[
160
+ Creates a **summary** metric – similar to histogram but intended
161
+ for quantile estimation (P-style summaries). Uses a single `observe`
162
+ method.
163
+
164
+ @return SummaryMetric handle.
165
+ ]]--
166
+ function Telemetry:Summary(name: string, opts: MetricOpts?): SummaryMetric
167
+ return ({
168
+
169
+ observe = function(_: SummaryMetric, value: number, lbls: LabelSet?)
170
+ pushSample(self, "sum", name, value, lbls or {})
171
+ end,
172
+
173
+ } :: any) :: SummaryMetric
174
+ end
175
+
176
+ return Telemetry