@typetorch/framework 0.5.3 → 0.5.4
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/out/assets/dom.d.ts +8 -0
- package/out/assets/dom.luau +64 -0
- package/out/assets/manifest.d.ts +2 -0
- package/out/assets/sync.luau +52 -7
- package/out/version.d.ts +1 -1
- package/out/version.luau +1 -1
- package/package.json +53 -53
package/out/assets/dom.d.ts
CHANGED
|
@@ -13,5 +13,13 @@ export declare function resolveParent(path: string, create: boolean): Instance |
|
|
|
13
13
|
* cloning a UI template into PlayerGui) keep the tag and the attributes but live elsewhere, so they never count.
|
|
14
14
|
*/
|
|
15
15
|
export declare function isLiveCopy(instance: Instance): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Copies the CollectionService tags of `from` and its descendants onto the instances at the same place in `to` (matched
|
|
18
|
+
* by name, and by order among siblings of the same name); AssetSync's own `__typetorch_asset:` tags stay out. A loaded
|
|
19
|
+
* hot-asset version arrives without the tags its place copy has (2026-10-13: a game that finds its UI by tag lost it
|
|
20
|
+
* on every server that loaded the uploads), so the load gives them back from the place's copy before it goes live.
|
|
21
|
+
* Returns how many tags were added.
|
|
22
|
+
*/
|
|
23
|
+
export declare function restoreTags(from: Instance, to: Instance): number;
|
|
16
24
|
/** The live copies tagged for `key` (normally one; two for a moment while a new version replaces the old). */
|
|
17
25
|
export declare function liveCopies(key: string): Instance[];
|
package/out/assets/dom.luau
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
local TS = _G[script]
|
|
3
3
|
local CollectionService = TS.import(script, TS.getModule(script, "@rbxts", "services")).CollectionService
|
|
4
4
|
local _manifest = TS.import(script, script.Parent, "manifest")
|
|
5
|
+
local ASSET_TAG_PREFIX = _manifest.ASSET_TAG_PREFIX
|
|
5
6
|
local assetTag = _manifest.assetTag
|
|
6
7
|
local ATTR_PATH = _manifest.ATTR_PATH
|
|
7
8
|
local pathSegments = _manifest.pathSegments
|
|
@@ -73,6 +74,68 @@ local function isLiveCopy(instance)
|
|
|
73
74
|
local parent = instance.Parent
|
|
74
75
|
return path ~= nil and parent ~= nil and resolveParent(path, false) == parent
|
|
75
76
|
end
|
|
77
|
+
--[[
|
|
78
|
+
*
|
|
79
|
+
* Copies the CollectionService tags of `from` and its descendants onto the instances at the same place in `to` (matched
|
|
80
|
+
* by name, and by order among siblings of the same name); AssetSync's own `__typetorch_asset:` tags stay out. A loaded
|
|
81
|
+
* hot-asset version arrives without the tags its place copy has (2026-10-13: a game that finds its UI by tag lost it
|
|
82
|
+
* on every server that loaded the uploads), so the load gives them back from the place's copy before it goes live.
|
|
83
|
+
* Returns how many tags were added.
|
|
84
|
+
|
|
85
|
+
]]
|
|
86
|
+
local function restoreTags(from, to)
|
|
87
|
+
local added = 0
|
|
88
|
+
local visit
|
|
89
|
+
visit = function(source, target)
|
|
90
|
+
for _, tag in source:GetTags() do
|
|
91
|
+
local _arg1 = #ASSET_TAG_PREFIX
|
|
92
|
+
local _condition = string.sub(tag, 1, _arg1) == ASSET_TAG_PREFIX
|
|
93
|
+
if not _condition then
|
|
94
|
+
_condition = target:HasTag(tag)
|
|
95
|
+
end
|
|
96
|
+
if _condition then
|
|
97
|
+
continue
|
|
98
|
+
end
|
|
99
|
+
target:AddTag(tag)
|
|
100
|
+
added += 1
|
|
101
|
+
end
|
|
102
|
+
local byName = {}
|
|
103
|
+
for _, child in target:GetChildren() do
|
|
104
|
+
local _name = child.Name
|
|
105
|
+
local list = byName[_name]
|
|
106
|
+
if list == nil then
|
|
107
|
+
local _name_1 = child.Name
|
|
108
|
+
local _arg1 = { child }
|
|
109
|
+
byName[_name_1] = _arg1
|
|
110
|
+
else
|
|
111
|
+
table.insert(list, child)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
local seen = {}
|
|
115
|
+
for _, child in source:GetChildren() do
|
|
116
|
+
local _name = child.Name
|
|
117
|
+
local _condition = seen[_name]
|
|
118
|
+
if _condition == nil then
|
|
119
|
+
_condition = 0
|
|
120
|
+
end
|
|
121
|
+
local index = _condition
|
|
122
|
+
local _name_1 = child.Name
|
|
123
|
+
local _arg1 = index + 1
|
|
124
|
+
seen[_name_1] = _arg1
|
|
125
|
+
local _name_2 = child.Name
|
|
126
|
+
local _match = byName[_name_2]
|
|
127
|
+
if _match ~= nil then
|
|
128
|
+
_match = _match[index + 1]
|
|
129
|
+
end
|
|
130
|
+
local match = _match
|
|
131
|
+
if match ~= nil then
|
|
132
|
+
visit(child, match)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
visit(from, to)
|
|
137
|
+
return added
|
|
138
|
+
end
|
|
76
139
|
--* The live copies tagged for `key` (normally one; two for a moment while a new version replaces the old).
|
|
77
140
|
local function liveCopies(key)
|
|
78
141
|
local _exp = CollectionService:GetTagged(assetTag(key))
|
|
@@ -93,5 +156,6 @@ return {
|
|
|
93
156
|
stringAttribute = stringAttribute,
|
|
94
157
|
resolveParent = resolveParent,
|
|
95
158
|
isLiveCopy = isLiveCopy,
|
|
159
|
+
restoreTags = restoreTags,
|
|
96
160
|
liveCopies = liveCopies,
|
|
97
161
|
}
|
package/out/assets/manifest.d.ts
CHANGED
|
@@ -144,6 +144,8 @@ export interface AssetStatus {
|
|
|
144
144
|
ms?: number;
|
|
145
145
|
/** Loaded after the start-up wait ran out. */
|
|
146
146
|
late?: boolean;
|
|
147
|
+
/** CollectionService tags a loaded copy got back from the place's copy (restoreTags). */
|
|
148
|
+
tags?: number;
|
|
147
149
|
}
|
|
148
150
|
export interface AssetSyncReport {
|
|
149
151
|
/** none: the artifact has no Assets attribute; invalid: unusable; unread: reading it failed (see errors). */
|
package/out/assets/sync.luau
CHANGED
|
@@ -9,6 +9,7 @@ local _dom = TS.import(script, script.Parent, "dom")
|
|
|
9
9
|
local liveCopies = _dom.liveCopies
|
|
10
10
|
local numberAttribute = _dom.numberAttribute
|
|
11
11
|
local resolveParent = _dom.resolveParent
|
|
12
|
+
local restoreTags = _dom.restoreTags
|
|
12
13
|
local stringAttribute = _dom.stringAttribute
|
|
13
14
|
local _manifest = TS.import(script, script.Parent, "manifest")
|
|
14
15
|
local assetTag = _manifest.assetTag
|
|
@@ -409,6 +410,50 @@ local function syncEntry(entry, status, placeMatches, ownEpoch, threads)
|
|
|
409
410
|
if target == nil then
|
|
410
411
|
error(`no {string.split(entry.path, "/")[1]} service`, 0)
|
|
411
412
|
end
|
|
413
|
+
-- The uploaded version has no CollectionService tags: the place's copy (on a hot swap, the copy being
|
|
414
|
+
-- replaced, which got them the same way) gives them back (restoreTags).
|
|
415
|
+
local _result_1
|
|
416
|
+
if fallback ~= nil and fallback.Parent ~= nil then
|
|
417
|
+
_result_1 = fallback
|
|
418
|
+
else
|
|
419
|
+
-- ▼ ReadonlyArray.find ▼
|
|
420
|
+
local _callback_2 = function(candidate)
|
|
421
|
+
return candidate.Parent ~= nil
|
|
422
|
+
end
|
|
423
|
+
local _result_2
|
|
424
|
+
for _i, _v in baked do
|
|
425
|
+
if _callback_2(_v, _i - 1, baked) == true then
|
|
426
|
+
_result_2 = _v
|
|
427
|
+
break
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
-- ▲ ReadonlyArray.find ▲
|
|
431
|
+
_result_1 = _result_2
|
|
432
|
+
end
|
|
433
|
+
local source = _result_1
|
|
434
|
+
do
|
|
435
|
+
local index = #tagged - 1
|
|
436
|
+
local _shouldIncrement = false
|
|
437
|
+
while true do
|
|
438
|
+
if _shouldIncrement then
|
|
439
|
+
index -= 1
|
|
440
|
+
else
|
|
441
|
+
_shouldIncrement = true
|
|
442
|
+
end
|
|
443
|
+
if not (source == nil and index >= 0) then
|
|
444
|
+
break
|
|
445
|
+
end
|
|
446
|
+
if tagged[index + 1].Parent ~= nil then
|
|
447
|
+
source = tagged[index + 1]
|
|
448
|
+
end
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
if source ~= nil then
|
|
452
|
+
local restored = restoreTags(source, copy)
|
|
453
|
+
if restored > 0 then
|
|
454
|
+
status.tags = restored
|
|
455
|
+
end
|
|
456
|
+
end
|
|
412
457
|
stamp(copy, entry, entry.ver)
|
|
413
458
|
copy.Parent = target
|
|
414
459
|
end)
|
|
@@ -425,7 +470,7 @@ local function syncEntry(entry, status, placeMatches, ownEpoch, threads)
|
|
|
425
470
|
if _condition == nil then
|
|
426
471
|
_condition = entry.ver
|
|
427
472
|
end
|
|
428
|
-
warn("[src/assets/sync.ts:
|
|
473
|
+
warn("[src/assets/sync.ts:308]", `hot asset {_exp_1} (version {_condition}) failed: {reason}`)
|
|
429
474
|
return nil
|
|
430
475
|
end
|
|
431
476
|
-- The new copy is live: the copies it replaces go.
|
|
@@ -438,7 +483,7 @@ local function syncEntry(entry, status, placeMatches, ownEpoch, threads)
|
|
|
438
483
|
status.ms = math.floor((os.clock() - started) * 1000)
|
|
439
484
|
if late then
|
|
440
485
|
status.late = true
|
|
441
|
-
print("[src/assets/sync.ts:
|
|
486
|
+
print("[src/assets/sync.ts:321]", `hot asset {entry.key} loaded late ({status.ms} ms)`)
|
|
442
487
|
end
|
|
443
488
|
end)
|
|
444
489
|
table.insert(_threads, _arg0)
|
|
@@ -495,7 +540,7 @@ local function run(kernel, deadline, ownEpoch, threads)
|
|
|
495
540
|
report.placeVersion = game.PlaceVersion
|
|
496
541
|
local placeMatches = place == "same" or place == "vouched"
|
|
497
542
|
if place == "differs" then
|
|
498
|
-
warn("[src/assets/sync.ts:
|
|
543
|
+
warn("[src/assets/sync.ts:366]", `hot assets: the manifest is for place v{manifest.placeVersion}, this server runs v{game.PlaceVersion}: keys without a matching baked copy load from their uploaded versions (typetorch assets sync --deploy <branch> fixes it)`)
|
|
499
544
|
end
|
|
500
545
|
local loads = {}
|
|
501
546
|
for _, entry in manifest.entries do
|
|
@@ -515,7 +560,7 @@ local function run(kernel, deadline, ownEpoch, threads)
|
|
|
515
560
|
if not ok then
|
|
516
561
|
status.source = "failed"
|
|
517
562
|
status.error = shortError(result)
|
|
518
|
-
warn("[src/assets/sync.ts:
|
|
563
|
+
warn("[src/assets/sync.ts:379]", `hot asset {entry.key} failed: {status.error}`)
|
|
519
564
|
elseif result ~= nil then
|
|
520
565
|
table.insert(loads, result)
|
|
521
566
|
end
|
|
@@ -549,7 +594,7 @@ local function run(kernel, deadline, ownEpoch, threads)
|
|
|
549
594
|
end
|
|
550
595
|
report.timedOut = true
|
|
551
596
|
load.fail("timed out")
|
|
552
|
-
warn("[src/assets/sync.ts:
|
|
597
|
+
warn("[src/assets/sync.ts:388]", `hot asset {load.status.key}: still loading; the old copy stays until it finishes`)
|
|
553
598
|
end
|
|
554
599
|
report.unmanaged = unmanagedKeys()
|
|
555
600
|
end
|
|
@@ -596,7 +641,7 @@ local function syncHotAssets(kernel, trove)
|
|
|
596
641
|
local _errors = report.errors
|
|
597
642
|
local _arg0 = `AssetSync failed: {shortError(err)}`
|
|
598
643
|
table.insert(_errors, _arg0)
|
|
599
|
-
warn("[src/assets/sync.ts:
|
|
644
|
+
warn("[src/assets/sync.ts:417]", `AssetSync failed: {err}`)
|
|
600
645
|
end
|
|
601
646
|
report.running = false
|
|
602
647
|
report.ms = math.floor((os.clock() - started) * 1000)
|
|
@@ -617,7 +662,7 @@ local function syncHotAssets(kernel, trove)
|
|
|
617
662
|
table.insert(parts, _arg0)
|
|
618
663
|
end
|
|
619
664
|
table.sort(parts)
|
|
620
|
-
print("[src/assets/sync.ts:
|
|
665
|
+
print("[src/assets/sync.ts:427]", `hot assets: {table.concat(parts, ", ")} in {report.ms} ms (place {report.place or "?"})`)
|
|
621
666
|
end
|
|
622
667
|
end
|
|
623
668
|
return {
|
package/out/version.d.ts
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* This framework's version, as package.json says (scripts/test-state-inspect.luau checks they match). Shown in
|
|
3
3
|
* uploaded log headers (Logs > Upload); bump it with package.json.
|
|
4
4
|
*/
|
|
5
|
-
export declare const FRAMEWORK_VERSION = "0.5.
|
|
5
|
+
export declare const FRAMEWORK_VERSION = "0.5.4";
|
package/out/version.luau
CHANGED
package/package.json
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@typetorch/framework",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "TypeTorch framework for roblox-ts: hot-swappable modules (dependency injection, lifecycle, troves), guarded networking, hot assets and the in-game dev menu. Ships inside every TypeTorch artifact.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "TypeTorch",
|
|
7
|
-
"homepage": "https://github.com/typetorch/framework#readme",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/typetorch/framework.git"
|
|
11
|
-
},
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/typetorch/framework/issues"
|
|
14
|
-
},
|
|
15
|
-
"keywords": ["roblox", "roblox-ts", "rbxts", "hot-reload", "hot-swap", "dependency-injection", "typetorch"],
|
|
16
|
-
"main": "out/init.luau",
|
|
17
|
-
"types": "out/index.d.ts",
|
|
18
|
-
"files": ["out", "!**/*.tsbuildinfo"],
|
|
19
|
-
"publishConfig": {
|
|
20
|
-
"access": "public"
|
|
21
|
-
},
|
|
22
|
-
"scripts": {
|
|
23
|
-
"build": "rbxtsc --type package",
|
|
24
|
-
"watch": "rbxtsc --type package -w",
|
|
25
|
-
"clean": "node -e \"require('fs').rmSync('out',{recursive:true,force:true})\"",
|
|
26
|
-
"prepublishOnly": "node -e \"require('fs').rmSync('out',{recursive:true,force:true})\" && rbxtsc --type package"
|
|
27
|
-
},
|
|
28
|
-
"peerDependencies": {
|
|
29
|
-
"@rbxts/compiler-types": "^3.0.0-types.0",
|
|
30
|
-
"@typetorch/transformer": "^0.2.0",
|
|
31
|
-
"roblox-ts": "^3.0.0"
|
|
32
|
-
},
|
|
33
|
-
"peerDependenciesMeta": {
|
|
34
|
-
"@typetorch/transformer": {
|
|
35
|
-
"optional": true
|
|
36
|
-
}
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"@rbxts/services": "^1.6.0",
|
|
40
|
-
"@rbxts/t": "^3.2.1",
|
|
41
|
-
"@rbxts/trove": "^1.3.0"
|
|
42
|
-
},
|
|
43
|
-
"devDependencies": {
|
|
44
|
-
"@rbxts/compiler-types": "^3.0.0-types.0",
|
|
45
|
-
"@rbxts/types": "^1.0.956",
|
|
46
|
-
"rbxts-transform-debug": "2.2.0",
|
|
47
|
-
"roblox-ts": "^3.0.0",
|
|
48
|
-
"typescript": "5.5.3"
|
|
49
|
-
},
|
|
50
|
-
"overrides": {
|
|
51
|
-
"typescript": "5.5.3"
|
|
52
|
-
}
|
|
53
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@typetorch/framework",
|
|
3
|
+
"version": "0.5.4",
|
|
4
|
+
"description": "TypeTorch framework for roblox-ts: hot-swappable modules (dependency injection, lifecycle, troves), guarded networking, hot assets and the in-game dev menu. Ships inside every TypeTorch artifact.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "TypeTorch",
|
|
7
|
+
"homepage": "https://github.com/typetorch/framework#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/typetorch/framework.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/typetorch/framework/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": ["roblox", "roblox-ts", "rbxts", "hot-reload", "hot-swap", "dependency-injection", "typetorch"],
|
|
16
|
+
"main": "out/init.luau",
|
|
17
|
+
"types": "out/index.d.ts",
|
|
18
|
+
"files": ["out", "!**/*.tsbuildinfo"],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "rbxtsc --type package",
|
|
24
|
+
"watch": "rbxtsc --type package -w",
|
|
25
|
+
"clean": "node -e \"require('fs').rmSync('out',{recursive:true,force:true})\"",
|
|
26
|
+
"prepublishOnly": "node -e \"require('fs').rmSync('out',{recursive:true,force:true})\" && rbxtsc --type package"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@rbxts/compiler-types": "^3.0.0-types.0",
|
|
30
|
+
"@typetorch/transformer": "^0.2.0",
|
|
31
|
+
"roblox-ts": "^3.0.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependenciesMeta": {
|
|
34
|
+
"@typetorch/transformer": {
|
|
35
|
+
"optional": true
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@rbxts/services": "^1.6.0",
|
|
40
|
+
"@rbxts/t": "^3.2.1",
|
|
41
|
+
"@rbxts/trove": "^1.3.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@rbxts/compiler-types": "^3.0.0-types.0",
|
|
45
|
+
"@rbxts/types": "^1.0.956",
|
|
46
|
+
"rbxts-transform-debug": "2.2.0",
|
|
47
|
+
"roblox-ts": "^3.0.0",
|
|
48
|
+
"typescript": "5.5.3"
|
|
49
|
+
},
|
|
50
|
+
"overrides": {
|
|
51
|
+
"typescript": "5.5.3"
|
|
52
|
+
}
|
|
53
|
+
}
|