@terrafirmagreg-team/recipe 0.1.0 → 1.2.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.
Files changed (240) hide show
  1. package/package.json +16 -16
  2. package/src/components/button-copy.tsx +1 -0
  3. package/src/components/cards/card/index.tsx +5 -3
  4. package/src/components/cards/card/scene.tsx +4 -2
  5. package/src/components/cards/card/strip.tsx +4 -2
  6. package/src/components/cards/card/text.tsx +2 -1
  7. package/src/components/cards/card/tips.tsx +1 -0
  8. package/src/components/cards/default-item.tsx +6 -2
  9. package/src/components/cards/glare-filter.tsx +1 -0
  10. package/src/components/cards/paged-card.tsx +1 -0
  11. package/src/components/cards/slot-hitbox.tsx +4 -2
  12. package/src/components/cards/strip-card/buttons.tsx +7 -2
  13. package/src/components/cards/strip-card/index.tsx +3 -1
  14. package/src/components/cards/strip-card/member-cell.tsx +4 -2
  15. package/src/components/cards/strip-card/sprite.tsx +1 -0
  16. package/src/components/embed-card.tsx +44 -0
  17. package/src/components/mdx/recipe.tsx +34 -16
  18. package/src/components/tool-list.tsx +1 -0
  19. package/src/{lib/tree.ts → components/tree.tsx} +20 -12
  20. package/src/components/views/alloy/index.tsx +14 -7
  21. package/src/components/views/alloy/list.tsx +3 -2
  22. package/src/components/views/alloy/mix/index.tsx +1 -0
  23. package/src/components/views/alloy/mix/ratio.tsx +7 -6
  24. package/src/components/views/alloy/mix/rows.tsx +6 -7
  25. package/src/components/views/alloy/mix/status.tsx +8 -7
  26. package/src/components/views/alloy/mix/total.tsx +13 -12
  27. package/src/components/views/alloy/range-bar.tsx +2 -1
  28. package/src/components/views/alloy/stack-bar.tsx +4 -2
  29. package/src/components/views/browser/axis-switcher.tsx +13 -12
  30. package/src/components/views/browser/card-grid.tsx +2 -1
  31. package/src/components/views/browser/favorite-button.tsx +2 -1
  32. package/src/components/views/browser/frame.tsx +3 -2
  33. package/src/components/views/browser/index.tsx +20 -2
  34. package/src/components/views/browser/item-panel/index.tsx +11 -9
  35. package/src/components/views/browser/item-panel/skeleton.tsx +1 -0
  36. package/src/components/views/browser/item-panel-grid/cell.tsx +5 -3
  37. package/src/components/views/browser/item-panel-grid/favorite-cell.tsx +4 -2
  38. package/src/components/views/browser/item-panel-grid/index.tsx +4 -2
  39. package/src/components/views/browser/item-view/index.tsx +7 -12
  40. package/src/components/views/browser/item-view/tags.tsx +7 -5
  41. package/src/components/views/browser/item-view-header.tsx +10 -9
  42. package/src/components/views/browser/pane-tabs.tsx +1 -0
  43. package/src/components/views/browser/place-header.tsx +4 -3
  44. package/src/components/views/browser/query-controls.tsx +3 -1
  45. package/src/components/views/browser/recipe-item-header.tsx +5 -4
  46. package/src/components/views/browser/settings.tsx +4 -3
  47. package/src/components/views/browser/toolbar.tsx +3 -2
  48. package/src/components/views/browser/type-tabs.tsx +5 -3
  49. package/src/components/views/browser/type-view.tsx +7 -12
  50. package/src/components/views/browser/workstation-rail.tsx +4 -3
  51. package/src/components/views/calc/calculator/actions.tsx +4 -14
  52. package/src/components/views/calc/calculator/help.tsx +69 -28
  53. package/src/components/views/calc/calculator/index.tsx +34 -82
  54. package/src/components/views/calc/dot-overlay.tsx +1 -0
  55. package/src/components/views/calc/edge.tsx +134 -32
  56. package/src/components/views/calc/flow/index.tsx +92 -54
  57. package/src/components/views/calc/flow/picker-dialogs.tsx +84 -6
  58. package/src/components/views/calc/flow/toolbar.tsx +9 -21
  59. package/src/components/views/calc/flow/view-menu.tsx +16 -120
  60. package/src/components/views/calc/member-picker.tsx +8 -6
  61. package/src/components/views/calc/node-card/actions.tsx +28 -106
  62. package/src/components/views/calc/node-card/badges.tsx +10 -28
  63. package/src/components/views/calc/node-card/chips.tsx +8 -40
  64. package/src/components/views/calc/node-card/far.tsx +13 -65
  65. package/src/components/views/calc/node-card/full.tsx +133 -83
  66. package/src/components/views/calc/node-card/index.tsx +1 -0
  67. package/src/components/views/calc/node-card/menu.tsx +93 -22
  68. package/src/components/views/calc/node-card/port-cells.tsx +186 -0
  69. package/src/components/views/calc/node-card/port-rails.tsx +251 -0
  70. package/src/components/views/calc/node-card/ports.tsx +86 -0
  71. package/src/components/views/calc/recipe-picker/body.tsx +17 -14
  72. package/src/components/views/calc/recipe-picker/footer.tsx +5 -3
  73. package/src/components/views/calc/recipe-picker/index.tsx +5 -0
  74. package/src/components/views/calc/sidebar.tsx +19 -10
  75. package/src/components/views/calc/trees/icon-picker.tsx +3 -2
  76. package/src/components/views/calc/trees/index.tsx +5 -4
  77. package/src/components/views/calc/trees/label.tsx +6 -4
  78. package/src/components/views/calc/trees/rows.tsx +6 -5
  79. package/src/components/views/forge/gui.tsx +2 -1
  80. package/src/components/views/forge/index.tsx +14 -7
  81. package/src/components/views/forge/list.tsx +3 -2
  82. package/src/components/views/forge/workbench/controls.tsx +13 -6
  83. package/src/components/views/forge/workbench/index.tsx +3 -2
  84. package/src/components/views/forge/workbench/panel.tsx +1 -0
  85. package/src/components/views/forge/workbench/ruler.tsx +5 -4
  86. package/src/components/views/forge/workbench/status.tsx +6 -5
  87. package/src/components/views/forge/workbench/tape.tsx +5 -4
  88. package/src/hooks/alloy/use-fluid-colors.ts +12 -9
  89. package/src/hooks/alloy/use-mix-state.ts +3 -2
  90. package/src/hooks/calc/flow/use-engage.ts +129 -0
  91. package/src/hooks/calc/flow/use-handlers.ts +192 -0
  92. package/src/hooks/calc/flow/use-layout.ts +105 -0
  93. package/src/hooks/calc/flow/{mount.ts → use-mount.ts} +1 -0
  94. package/src/hooks/calc/flow/{nodes.ts → use-nodes.ts} +46 -37
  95. package/src/hooks/calc/flow/use-pickers.ts +57 -0
  96. package/src/hooks/calc/flow/{viewport.ts → use-viewport.ts} +13 -26
  97. package/src/hooks/calc/flow/{window.ts → use-window.ts} +1 -0
  98. package/src/hooks/calc/use-actions.ts +208 -229
  99. package/src/hooks/calc/use-amounts.ts +23 -60
  100. package/src/hooks/calc/use-data.ts +106 -192
  101. package/src/hooks/calc/use-defaults.ts +4 -2
  102. package/src/hooks/calc/use-far-mode.ts +1 -0
  103. package/src/hooks/calc/use-focus.ts +8 -7
  104. package/src/hooks/calc/use-maps.ts +1 -0
  105. package/src/hooks/calc/use-reset.ts +1 -0
  106. package/src/hooks/calc/use-resolver.ts +32 -196
  107. package/src/hooks/calc/use-session.ts +1 -0
  108. package/src/hooks/calc/use-share.ts +5 -2
  109. package/src/hooks/calc/use-storage.ts +5 -4
  110. package/src/hooks/calc/use-tier.ts +1 -0
  111. package/src/hooks/calc/use-view-mode.ts +1 -0
  112. package/src/hooks/calc/use-worker.ts +56 -121
  113. package/src/hooks/forge/use-anvil-gui.ts +4 -2
  114. package/src/hooks/forge/use-forge-state.ts +1 -0
  115. package/src/hooks/forge/use-ruler.ts +1 -0
  116. package/src/hooks/use-add-to-calc.ts +23 -19
  117. package/src/hooks/use-categories-by-id.ts +18 -0
  118. package/src/hooks/use-favorite-hotkey.ts +1 -0
  119. package/src/hooks/use-favorites.ts +1 -0
  120. package/src/hooks/use-group-outlines.ts +1 -0
  121. package/src/hooks/use-hide-unused.ts +2 -1
  122. package/src/hooks/use-index.ts +6 -2
  123. package/src/hooks/use-item-feeds.ts +3 -1
  124. package/src/hooks/use-item-pane.ts +6 -4
  125. package/src/hooks/use-item-press.ts +27 -23
  126. package/src/hooks/use-item-tag-groups.ts +4 -2
  127. package/src/hooks/use-item-tooltips.ts +3 -1
  128. package/src/hooks/use-left-sidebar-tree.ts +11 -3
  129. package/src/hooks/use-mod-names.ts +4 -2
  130. package/src/hooks/use-mount-limit.ts +1 -0
  131. package/src/hooks/use-panel-cells.ts +3 -1
  132. package/src/hooks/use-panel-page.ts +9 -6
  133. package/src/hooks/use-panel-tabs.ts +2 -1
  134. package/src/hooks/use-query.ts +8 -6
  135. package/src/hooks/use-session.ts +6 -2
  136. package/src/hooks/use-sidebar-group.ts +3 -7
  137. package/src/hooks/use-tag-members.ts +3 -1
  138. package/src/hooks/use-tool-recipes.ts +1 -0
  139. package/src/hooks/use-type-filter.ts +1 -0
  140. package/src/lib/alloy/mix.ts +1 -0
  141. package/src/lib/alloy/parse.ts +1 -0
  142. package/src/lib/calc/defaults.ts +6 -4
  143. package/src/lib/calc/flow.ts +143 -107
  144. package/src/lib/calc/focus.ts +1 -0
  145. package/src/lib/calc/meta.ts +3 -1
  146. package/src/lib/calc/pack.ts +47 -154
  147. package/src/lib/calc/ports.ts +43 -0
  148. package/src/lib/calc/resolve.ts +6 -38
  149. package/src/lib/calc/route/buckets.ts +1 -0
  150. package/src/lib/calc/route/geometry.ts +13 -24
  151. package/src/lib/calc/route/index.ts +1 -0
  152. package/src/lib/calc/route/polyline.ts +3 -3
  153. package/src/lib/calc/route/router.ts +181 -57
  154. package/src/lib/calc/scheme.ts +226 -0
  155. package/src/lib/calc/storage/entry.ts +27 -19
  156. package/src/lib/calc/storage/index.ts +2 -0
  157. package/src/lib/calc/storage/keys.ts +4 -8
  158. package/src/lib/calc/storage/store.ts +11 -36
  159. package/src/lib/calc/tree/index.ts +2 -16
  160. package/src/lib/calc/tree/materials.ts +1 -0
  161. package/src/lib/calc/tree/recipe.ts +1 -0
  162. package/src/lib/calc/tree/share.ts +86 -149
  163. package/src/lib/calc/worker/api.ts +3 -11
  164. package/src/lib/calc/worker/fetch.ts +1 -0
  165. package/src/lib/calc/worker/flush.ts +7 -20
  166. package/src/lib/calc/worker/index.ts +1 -1
  167. package/src/lib/calc/worker/protocol.ts +16 -13
  168. package/src/lib/calc/worker/resolve.ts +32 -84
  169. package/src/lib/calc/worker/state.ts +5 -6
  170. package/src/{components/cards/card/model.ts → lib/card-model.ts} +1 -0
  171. package/src/lib/client/recipe-categories.ts +11 -93
  172. package/src/lib/client/recipe.ts +13 -11
  173. package/src/lib/client-index/catalog.ts +33 -27
  174. package/src/lib/client-index/chrome.ts +30 -30
  175. package/src/lib/client-index/index.ts +1 -0
  176. package/src/lib/client-index/registry.ts +70 -59
  177. package/src/lib/client-index/rows.ts +63 -57
  178. package/src/lib/client-index/tooltips.ts +28 -34
  179. package/src/lib/config.ts +2 -1
  180. package/src/lib/data/category/dto.ts +4 -3
  181. package/src/lib/data/category/load.ts +9 -8
  182. package/src/lib/data/category/parse.ts +4 -3
  183. package/src/lib/data/dto.ts +4 -3
  184. package/src/lib/data/grid.ts +2 -1
  185. package/src/lib/data/parse/entry.ts +3 -2
  186. package/src/lib/data/parse/index.ts +1 -0
  187. package/src/lib/data/parse/layout.ts +5 -2
  188. package/src/lib/data/parse/slots.ts +3 -2
  189. package/src/lib/data/parse/widgets.ts +3 -2
  190. package/src/lib/data/scene.ts +1 -1
  191. package/src/lib/data/slot-io.ts +1 -0
  192. package/src/lib/dump.ts +4 -3
  193. package/src/lib/embed.ts +22 -0
  194. package/src/lib/favorite-hover.ts +1 -0
  195. package/src/lib/fluid-outputs.ts +10 -12
  196. package/src/lib/forge/actions.ts +2 -1
  197. package/src/lib/forge/data.ts +2 -1
  198. package/src/lib/forge/solve.ts +1 -0
  199. package/src/lib/group.ts +1 -0
  200. package/src/lib/index-store.ts +15 -9
  201. package/src/lib/links.ts +15 -9
  202. package/src/lib/lookup.ts +10 -8
  203. package/src/lib/panel-outline.ts +1 -0
  204. package/src/lib/panel.ts +3 -2
  205. package/src/lib/preview.ts +12 -8
  206. package/src/lib/recipe-slots.ts +1 -0
  207. package/src/lib/search.ts +1 -0
  208. package/src/lib/sidebar.ts +1 -0
  209. package/src/lib/used-items.ts +1 -0
  210. package/src/locales/en_us.json +170 -226
  211. package/src/locales/ru_ru.json +170 -226
  212. package/src/locales.ts +1 -0
  213. package/src/types/alloy.ts +1 -0
  214. package/src/{hooks/calc/flow/props.ts → types/calc-flow-props.ts} +18 -14
  215. package/src/types/calc.ts +41 -44
  216. package/src/types/forge.ts +1 -0
  217. package/src/types/index.ts +4 -2
  218. package/styles/calc.css +308 -47
  219. package/src/components/cards/fit-card.tsx +0 -26
  220. package/src/components/views/calc/target.tsx +0 -271
  221. package/src/hooks/calc/flow/engage.ts +0 -89
  222. package/src/hooks/calc/flow/handlers.ts +0 -115
  223. package/src/hooks/calc/flow/layout.ts +0 -149
  224. package/src/hooks/calc/flow/pickers.ts +0 -50
  225. package/src/hooks/calc/use-calc-fill.ts +0 -91
  226. package/src/hooks/calc/use-density.ts +0 -28
  227. package/src/hooks/calc/use-derived.ts +0 -258
  228. package/src/hooks/calc/use-direction.ts +0 -23
  229. package/src/hooks/calc/use-edge-style.ts +0 -40
  230. package/src/hooks/calc/use-fill.ts +0 -213
  231. package/src/lib/alloy/alloy.test.ts +0 -186
  232. package/src/lib/calc/tree/build.ts +0 -196
  233. package/src/lib/calc/tree/context.ts +0 -42
  234. package/src/lib/calc/tree/goal.ts +0 -64
  235. package/src/lib/calc/tree/ideal.ts +0 -36
  236. package/src/lib/calc/tree/pick.ts +0 -68
  237. package/src/lib/calc/tree/tree.test.ts +0 -169
  238. package/src/lib/calc/worker/fill.ts +0 -123
  239. package/src/lib/client-index/cache.ts +0 -13
  240. package/src/lib/forge/forge.test.ts +0 -123
@@ -1,15 +1,16 @@
1
+ import type { DatasetRef } from '@terrafirmagreg-team/sites/location';
1
2
  import type {
2
3
  RecipeCompactIndex,
3
4
  RecipeCompactRow,
4
5
  } from '@terrafirmagreg-team/recipe/types';
5
- import { clientDumpJson, loadClientManifest } from '@terrafirmagreg-team/game/lib/dump/client/dump';
6
- import { dumpRelPublicUrl } from '@terrafirmagreg-team/game/lib/dump/paths';
7
- import { asNumber, asRecord, asString } from '@terrafirmagreg-team/game/lib/dump/contract/read';
6
+ import { clientDumpJson, loadClientManifest } from '@terrafirmagreg-team/dump/lib/dump/client/dump';
7
+ import { dumpRelPublicUrl } from '@terrafirmagreg-team/dump/lib/dump/paths';
8
+ import { asNumber, asRecord, asString } from '@terrafirmagreg-team/dump/lib/dump/contract/read';
8
9
  import {
9
10
  asTaggedReference,
10
11
  stackIdFromRef,
11
- } from '@terrafirmagreg-team/game/lib/dump/contract/ref';
12
- import type { RecipeTypeRow } from '@terrafirmagreg-team/game/lib/dump/manifest/dto';
12
+ } from '@terrafirmagreg-team/dump/lib/dump/contract/ref';
13
+ import type { RecipeTypeRow } from '@terrafirmagreg-team/dump/lib/dump/manifest/dto';
13
14
  import {
14
15
  clientRecipeFileRels,
15
16
  loadClientRecipe,
@@ -23,13 +24,58 @@ import type {
23
24
  Recipe,
24
25
  RecipeSlotType,
25
26
  } from '@terrafirmagreg-team/recipe/lib/data/dto';
26
- import { memoPending } from './cache';
27
+ import { createDatasetCache } from '@terrafirmagreg-team/dump/lib/dump/reader';
27
28
 
28
- const typeRowsCache = new Map<string, Promise<RecipeCompactRow[]>>();
29
- const bucketCache = new Map<string, Promise<Record<string, unknown>>>();
29
+ const typeRowsCache = createDatasetCache(
30
+ async (
31
+ dataset: DatasetRef,
32
+ index: RecipeCompactIndex,
33
+ typeId: string,
34
+ ): Promise<RecipeCompactRow[]> => {
35
+ const typeIndex = index.types.indexOf(typeId);
36
+ if (typeIndex < 0) return [];
37
+ const row = (await recipeTypeRows(dataset)).find(
38
+ (entry) => entry.id === typeId,
39
+ );
40
+ if (!row?.files) return [];
41
+ const layout = categoryLayout(index, typeId);
42
+ const buckets = await Promise.all(
43
+ Object.values(row.files).map(async (rel) => {
44
+ if (!rel) return [];
45
+ const bucket = await loadBucket(dataset, rel);
46
+ return Object.entries(bucket).flatMap(([id, raw]) => {
47
+ const parsed = rowFromBucketEntry(
48
+ dataset,
49
+ id,
50
+ raw,
51
+ typeIndex,
52
+ rel,
53
+ layout,
54
+ );
55
+ return parsed ? [parsed] : [];
56
+ });
57
+ }),
58
+ );
59
+ return buckets
60
+ .flat()
61
+ .sort(
62
+ (a, b) =>
63
+ (a.o ?? Number.MAX_SAFE_INTEGER) - (b.o ?? Number.MAX_SAFE_INTEGER),
64
+ );
65
+ },
66
+ (dataset, _index, typeId) => `${dataset.id}/${dataset.version ?? ''} ${typeId}`,
67
+ );
68
+
69
+ const bucketCache = createDatasetCache(
70
+ async (dataset: DatasetRef, rel: string): Promise<Record<string, unknown>> => {
71
+ const raw = await clientDumpJson(dataset, rel, 'high');
72
+ return asRecord(raw) ?? {};
73
+ },
74
+ (dataset, rel) => `${dataset.id}/${dataset.version ?? ''} ${rel}`,
75
+ );
30
76
 
31
77
  export async function recipeTypeRows(
32
- dataset: string,
78
+ dataset: DatasetRef,
33
79
  ): Promise<RecipeTypeRow[]> {
34
80
  const manifest = await loadClientManifest(dataset);
35
81
  return manifest?.indexes.recipes.types ?? [];
@@ -85,7 +131,7 @@ function slotRefIds(
85
131
  }
86
132
 
87
133
  function rowFromBucketEntry(
88
- dataset: string,
134
+ dataset: DatasetRef,
89
135
  id: string,
90
136
  raw: unknown,
91
137
  typeIndex: number,
@@ -112,63 +158,22 @@ function rowFromBucketEntry(
112
158
  }
113
159
 
114
160
  function loadBucket(
115
- dataset: string,
161
+ dataset: DatasetRef,
116
162
  rel: string,
117
163
  ): Promise<Record<string, unknown>> {
118
- const key = `${dataset} ${rel}`;
119
- const cached = bucketCache.get(key);
120
- if (cached) return cached;
121
- const pending = clientDumpJson(dataset, rel, 'high').then(
122
- (raw) => asRecord(raw) ?? {},
123
- );
124
- return memoPending(bucketCache, key, pending);
164
+ return bucketCache(dataset, rel);
125
165
  }
126
166
 
127
167
  export function loadTypeRows(
128
- dataset: string,
168
+ dataset: DatasetRef,
129
169
  index: RecipeCompactIndex,
130
170
  typeId: string,
131
171
  ): Promise<RecipeCompactRow[]> {
132
- const key = `${dataset} ${typeId}`;
133
- const cached = typeRowsCache.get(key);
134
- if (cached) return cached;
135
- const pending = (async (): Promise<RecipeCompactRow[]> => {
136
- const typeIndex = index.types.indexOf(typeId);
137
- if (typeIndex < 0) return [];
138
- const row = (await recipeTypeRows(dataset)).find(
139
- (entry) => entry.id === typeId,
140
- );
141
- if (!row?.files) return [];
142
- const layout = categoryLayout(index, typeId);
143
- const buckets = await Promise.all(
144
- Object.values(row.files).map(async (rel) => {
145
- if (!rel) return [];
146
- const bucket = await loadBucket(dataset, rel);
147
- return Object.entries(bucket).flatMap(([id, raw]) => {
148
- const parsed = rowFromBucketEntry(
149
- dataset,
150
- id,
151
- raw,
152
- typeIndex,
153
- rel,
154
- layout,
155
- );
156
- return parsed ? [parsed] : [];
157
- });
158
- }),
159
- );
160
- return buckets
161
- .flat()
162
- .sort(
163
- (a, b) =>
164
- (a.o ?? Number.MAX_SAFE_INTEGER) - (b.o ?? Number.MAX_SAFE_INTEGER),
165
- );
166
- })();
167
- return memoPending(typeRowsCache, key, pending);
172
+ return typeRowsCache(dataset, index, typeId);
168
173
  }
169
174
 
170
175
  export async function loadCategoryRecipes(
171
- dataset: string,
176
+ dataset: DatasetRef,
172
177
  index: RecipeCompactIndex,
173
178
  typeId: string,
174
179
  ): Promise<Recipe[]> {
@@ -189,7 +194,7 @@ export async function loadCategoryRecipes(
189
194
  export const TAG_RECIPE_TYPE = 'emi:tag';
190
195
 
191
196
  export async function resolveRecipeRows(
192
- dataset: string,
197
+ dataset: DatasetRef,
193
198
  index: RecipeCompactIndex,
194
199
  ids: Iterable<string>,
195
200
  opts?: { includeTagRows?: boolean },
@@ -252,3 +257,4 @@ export async function resolveRecipeRows(
252
257
  );
253
258
  return deduped;
254
259
  }
260
+
@@ -1,34 +1,23 @@
1
- import { clientDumpLang } from '@terrafirmagreg-team/game/lib/dump/client/dump';
2
- import { loadClientKeybinds } from '@terrafirmagreg-team/game/lib/dump/client/keybinds';
1
+ import type { DatasetRef } from '@terrafirmagreg-team/sites/location';
2
+ import { clientDumpLang } from '@terrafirmagreg-team/dump/lib/dump/client/dump';
3
+ import { loadClientKeybinds } from '@terrafirmagreg-team/dump/lib/dump/client/keybinds';
3
4
  import {
4
5
  loadClientRegistryTooltips,
5
6
  loadClientRegistryTooltipsMod,
6
- } from '@terrafirmagreg-team/game/lib/dump/client/registry';
7
- import { dumpTextLines } from '@terrafirmagreg-team/game/lib/dump/assets/lang/names';
8
- import { memoPending } from './cache';
9
-
10
- const tooltipsCache = new Map<string, Promise<Record<string, string[]>>>();
11
- const tooltipsApiCache = new Map<
12
- string,
13
- Promise<{
14
- lines: Record<string, string[]>;
15
- mods: Record<string, Record<string, string[]>>;
16
- }>
17
- >();
7
+ } from '@terrafirmagreg-team/dump/lib/dump/client/registry';
8
+ import { dumpTextLines } from '@terrafirmagreg-team/dump/lib/dump/assets/lang/names';
9
+ import { createDatasetCache } from '@terrafirmagreg-team/dump/lib/dump/reader';
18
10
 
19
11
  const TOOLTIP_MODS = ['shift', 'ctrl', 'alt'] as const;
20
12
 
21
- function loadItemTooltipsApi(
22
- dataset: string,
23
- lang: string,
24
- ): Promise<{
25
- lines: Record<string, string[]>;
26
- mods: Record<string, Record<string, string[]>>;
27
- }> {
28
- const key = `${dataset} ${lang}`;
29
- const cached = tooltipsApiCache.get(key);
30
- if (cached) return cached;
31
- const pending = (async () => {
13
+ const tooltipsApiCache = createDatasetCache(
14
+ async (
15
+ dataset: DatasetRef,
16
+ lang: string,
17
+ ): Promise<{
18
+ lines: Record<string, string[]>;
19
+ mods: Record<string, Record<string, string[]>>;
20
+ }> => {
32
21
  const kinds = ['item', 'block', 'fluid', 'entity'] as const;
33
22
  const [map, keybinds, shards, modShards] = await Promise.all([
34
23
  clientDumpLang(dataset, lang),
@@ -64,17 +53,22 @@ function loadItemTooltipsApi(
64
53
  }
65
54
  }
66
55
  return { lines, mods };
67
- })();
68
- return memoPending(tooltipsApiCache, key, pending);
69
- }
56
+ },
57
+ );
58
+
59
+ const tooltipsCache = createDatasetCache(
60
+ async (
61
+ dataset: DatasetRef,
62
+ lang: string,
63
+ ): Promise<Record<string, string[]>> =>
64
+ (await tooltipsApiCache(dataset, lang)).lines,
65
+ (dataset, lang) => `${dataset.id}/${dataset.version ?? ''} ${lang}`,
66
+ );
70
67
 
71
68
  export async function loadItemTooltips(
72
- dataset: string,
69
+ dataset: DatasetRef,
73
70
  lang: string,
74
71
  ): Promise<Record<string, string[]>> {
75
- const key = `${dataset} ${lang}`;
76
- const cached = tooltipsCache.get(key);
77
- if (cached) return cached;
78
- const pending = loadItemTooltipsApi(dataset, lang).then((api) => api.lines);
79
- return memoPending(tooltipsCache, key, pending);
72
+ return tooltipsCache(dataset, lang);
80
73
  }
74
+
package/src/lib/config.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createConfigRegistry, uiConfig } from '@terrafirmagreg-team/ui/lib/config';
2
- import { registerMdxComponents } from '@terrafirmagreg-team/kit/lib/mdx-components';
2
+ import { registerMdxComponents } from '@terrafirmagreg-team/mdx/components/mdx-components';
3
3
  import { Recipe } from '@terrafirmagreg-team/recipe/components/mdx/recipe';
4
4
  import '@terrafirmagreg-team/recipe/lib/preview';
5
5
 
@@ -15,3 +15,4 @@ const { register: registerRecipeConfig, get: recipeConfig } =
15
15
  export { registerRecipeConfig, recipeConfig };
16
16
 
17
17
  registerMdxComponents({ Recipe });
18
+
@@ -1,10 +1,10 @@
1
- import type { DumpDisplay } from '@terrafirmagreg-team/game/lib/dump/contract/text';
2
- import type { TaggedReference } from '@terrafirmagreg-team/game/lib/dump/contract/ref';
1
+ import type { DumpDisplay } from '@terrafirmagreg-team/dump/lib/dump/contract/text';
2
+ import type { TaggedReference } from '@terrafirmagreg-team/dump/lib/dump/contract/ref';
3
3
  import type {
4
4
  RecipeCategory,
5
5
  RecipeCategoryLayout,
6
6
  RecipeLayoutSlot,
7
- } from '@terrafirmagreg-team/game/lib/dump/gen';
7
+ } from '@terrafirmagreg-team/dump/lib/dump/gen';
8
8
 
9
9
  export type DumpLayoutSlot = RecipeLayoutSlot;
10
10
 
@@ -22,3 +22,4 @@ export type DumpRecipeCategory = Omit<
22
22
  workstations?: TaggedReference[];
23
23
  layout?: DumpRecipeLayout;
24
24
  };
25
+
@@ -1,13 +1,13 @@
1
- import 'server-only';
1
+ import type { DatasetRef } from '@terrafirmagreg-team/sites/location';
2
2
  import { asCategory } from '@terrafirmagreg-team/recipe/lib/data/category/parse';
3
3
  import type { DumpRecipeCategory } from '@terrafirmagreg-team/recipe/lib/data/category/dto';
4
- import { loadDatasetDump } from '@terrafirmagreg-team/game/lib/dump/mods/load';
5
- import { clientDumpJson } from '@terrafirmagreg-team/game/lib/dump/client/dump';
6
- import { asRecord } from '@terrafirmagreg-team/game/lib/dump/contract/read';
7
- import { createAsyncCache } from '@terrafirmagreg-team/ui/lib/utils/async-cache';
4
+ import { loadDatasetDump } from '@terrafirmagreg-team/dump/lib/dump/mods/load';
5
+ import { clientDumpJson } from '@terrafirmagreg-team/dump/lib/dump/client/dump';
6
+ import { asRecord } from '@terrafirmagreg-team/dump/lib/dump/contract/read';
7
+ import { createDatasetCache } from '@terrafirmagreg-team/dump/lib/dump/reader';
8
8
 
9
- const cache = createAsyncCache(
10
- async (dataset: string): Promise<DumpRecipeCategory[]> => {
9
+ const cache = createDatasetCache(
10
+ async (dataset: DatasetRef): Promise<DumpRecipeCategory[]> => {
11
11
  const out: DumpRecipeCategory[] = [];
12
12
  const dump = await loadDatasetDump(dataset);
13
13
  if (dump) {
@@ -40,7 +40,8 @@ const cache = createAsyncCache(
40
40
  );
41
41
 
42
42
  export function loadDatasetRecipeCategories(
43
- dataset: string,
43
+ dataset: DatasetRef,
44
44
  ): Promise<DumpRecipeCategory[]> {
45
45
  return cache(dataset);
46
46
  }
47
+
@@ -1,6 +1,6 @@
1
- import { asNumber, asRecord, asString } from '@terrafirmagreg-team/game/lib/dump/contract/read';
2
- import { asTaggedReference } from '@terrafirmagreg-team/game/lib/dump/contract/ref';
3
- import { asDisplay } from '@terrafirmagreg-team/game/lib/dump/contract/text';
1
+ import { asNumber, asRecord, asString } from '@terrafirmagreg-team/dump/lib/dump/contract/read';
2
+ import { asTaggedReference } from '@terrafirmagreg-team/dump/lib/dump/contract/ref';
3
+ import { asDisplay } from '@terrafirmagreg-team/dump/lib/dump/contract/text';
4
4
  import type {
5
5
  DumpLayoutSlot,
6
6
  DumpRecipeCategory,
@@ -68,3 +68,4 @@ export function asCategory(value: unknown): DumpRecipeCategory | undefined {
68
68
  ...(layout ? { layout } : {}),
69
69
  };
70
70
  }
71
+
@@ -1,6 +1,6 @@
1
- import type { TaggedReference } from '@terrafirmagreg-team/game/lib/dump/contract/ref';
2
- import type { DumpText } from '@terrafirmagreg-team/game/lib/dump/contract/text';
3
- import type { RecipeEntry, RecipeSlot } from '@terrafirmagreg-team/game/lib/dump/gen';
1
+ import type { TaggedReference } from '@terrafirmagreg-team/dump/lib/dump/contract/ref';
2
+ import type { DumpText } from '@terrafirmagreg-team/dump/lib/dump/contract/text';
3
+ import type { RecipeEntry, RecipeSlot } from '@terrafirmagreg-team/dump/lib/dump/gen';
4
4
 
5
5
  export const RECIPE_SLOT_TYPES = [
6
6
  'input',
@@ -149,3 +149,4 @@ export type Recipe = Omit<
149
149
  h?: number;
150
150
  extra: Record<string, unknown>;
151
151
  };
152
+
@@ -2,7 +2,7 @@ import {
2
2
  asNumber,
3
3
  asRecord,
4
4
  asString,
5
- } from '@terrafirmagreg-team/game/lib/dump/contract/read';
5
+ } from '@terrafirmagreg-team/dump/lib/dump/contract/read';
6
6
  import type { RecipeGrid, RecipeGridMember } from '@terrafirmagreg-team/recipe/lib/data/dto';
7
7
 
8
8
  export function recipeGrid(
@@ -37,3 +37,4 @@ export function recipeGrid(
37
37
  const tail = asNumber(raw.tail) ?? 0;
38
38
  return { grid: { y, row, tail, cols, rows }, members };
39
39
  }
40
+
@@ -1,5 +1,5 @@
1
- import { stackDisplayName } from '@terrafirmagreg-team/game/lib/dump/assets/lang/names';
2
- import { asNumber, asRecord, asString } from '@terrafirmagreg-team/game/lib/dump/contract/read';
1
+ import { stackDisplayName } from '@terrafirmagreg-team/dump/lib/dump/assets/lang/names';
2
+ import { asNumber, asRecord, asString } from '@terrafirmagreg-team/dump/lib/dump/contract/read';
3
3
  import type { DumpRecipeLayout } from '@terrafirmagreg-team/recipe/lib/data/category/dto';
4
4
  import type { Recipe } from '@terrafirmagreg-team/recipe/lib/data/dto';
5
5
  import { hydrateRecipe } from './layout';
@@ -82,3 +82,4 @@ export function recipeTitle(
82
82
  }
83
83
  return recipe.id;
84
84
  }
85
+
@@ -1,2 +1,3 @@
1
1
  export { parseRecipe, recipeTitle } from './entry';
2
2
  export { hydrateRecipe } from './layout';
3
+
@@ -1,4 +1,4 @@
1
- import { stackIdFromRef } from '@terrafirmagreg-team/game/lib/dump/contract/ref';
1
+ import { stackIdFromRef } from '@terrafirmagreg-team/dump/lib/dump/contract/ref';
2
2
  import type { DumpRecipeLayout } from '@terrafirmagreg-team/recipe/lib/data/category/dto';
3
3
  import type {
4
4
  Recipe,
@@ -121,7 +121,9 @@ export function hydrateRecipe(recipe: Recipe, layout?: DumpRecipeLayout): Recipe
121
121
  recipe,
122
122
  new Set((layout?.slots ?? []).map((slot) => slot.id)),
123
123
  ),
124
- ...recipe.widgets,
124
+ ...(recipe.widgets as RecipeWidget[]).filter(
125
+ (widget) => widget.type !== 'slot',
126
+ ),
125
127
  ],
126
128
  ...(layout
127
129
  ? {
@@ -133,3 +135,4 @@ export function hydrateRecipe(recipe: Recipe, layout?: DumpRecipeLayout): Recipe
133
135
  : {}),
134
136
  };
135
137
  }
138
+
@@ -2,8 +2,8 @@ import {
2
2
  asTaggedReference,
3
3
  stackIdFromRef,
4
4
  type TaggedReference,
5
- } from '@terrafirmagreg-team/game/lib/dump/contract/ref';
6
- import { asNumber, asRecord } from '@terrafirmagreg-team/game/lib/dump/contract/read';
5
+ } from '@terrafirmagreg-team/dump/lib/dump/contract/ref';
6
+ import { asNumber, asRecord } from '@terrafirmagreg-team/dump/lib/dump/contract/read';
7
7
  import type {
8
8
  IngredientKind,
9
9
  RecipeSlotFill,
@@ -82,3 +82,4 @@ export function parseSlots(value: unknown): Record<string, RecipeSlotFill> {
82
82
  }
83
83
  return out;
84
84
  }
85
+
@@ -1,5 +1,5 @@
1
- import { asNumber, asRecord, asString } from '@terrafirmagreg-team/game/lib/dump/contract/read';
2
- import { asDumpText } from '@terrafirmagreg-team/game/lib/dump/contract/text';
1
+ import { asNumber, asRecord, asString } from '@terrafirmagreg-team/dump/lib/dump/contract/read';
2
+ import { asDumpText } from '@terrafirmagreg-team/dump/lib/dump/contract/text';
3
3
  import type { RecipeWidget } from '@terrafirmagreg-team/recipe/lib/data/dto';
4
4
 
5
5
  function parseDecorWidget(value: unknown): RecipeWidget | undefined {
@@ -78,3 +78,4 @@ export function parseDecorWidgets(value: unknown): RecipeWidget[] {
78
78
  return widget ? [widget] : [];
79
79
  });
80
80
  }
81
+
@@ -2,7 +2,7 @@ import {
2
2
  asNumber,
3
3
  asRecord,
4
4
  asString,
5
- } from '@terrafirmagreg-team/game/lib/dump/contract/read';
5
+ } from '@terrafirmagreg-team/dump/lib/dump/contract/read';
6
6
 
7
7
  export type RecipeSceneRect = {
8
8
  x: number;
@@ -41,3 +41,4 @@ export function slotIoRole(
41
41
  }
42
42
  return 'input';
43
43
  }
44
+
package/src/lib/dump.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type { DumpIndex } from '@terrafirmagreg-team/game/lib/dump/mods/dto';
2
-
3
- export function recipeDumpHasContent(dump: DumpIndex): boolean {
1
+ export function recipeDumpHasContent(dump: {
2
+ mods: readonly { recipeIndex: string | null }[];
3
+ }): boolean {
4
4
  return dump.mods.some((mod) => mod.recipeIndex != null);
5
5
  }
6
+
@@ -0,0 +1,22 @@
1
+ import { RecipeEmbedCard } from '@terrafirmagreg-team/recipe/components/embed-card';
2
+ import { loadClientRecipe } from '@terrafirmagreg-team/recipe/lib/client/recipe';
3
+ import {
4
+ recipeCardImageUrl,
5
+ recipeHref,
6
+ } from '@terrafirmagreg-team/recipe/lib/links';
7
+ import { recipeTitle } from '@terrafirmagreg-team/recipe/lib/data/parse';
8
+ import type { Recipe } from '@terrafirmagreg-team/recipe/lib/data/dto';
9
+ import type {
10
+ EmbedRecipe,
11
+ SectionEmbeds,
12
+ } from '@terrafirmagreg-team/kit/types/embeds';
13
+
14
+ export const recipeSectionEmbed: NonNullable<SectionEmbeds['recipe']> = {
15
+ href: (dataset, lang, ref) => recipeHref(dataset, lang, { id: ref.id }),
16
+ cardImageUrl: recipeCardImageUrl,
17
+ load: async (dataset, id) =>
18
+ (await loadClientRecipe(dataset, id)) as EmbedRecipe | undefined,
19
+ title: (recipe, langMap) =>
20
+ recipeTitle(recipe as unknown as Recipe, langMap),
21
+ Card: RecipeEmbedCard,
22
+ };
@@ -10,3 +10,4 @@ export const favoriteHover: {
10
10
  export function favoriteHoverTarget(): FavoriteHoverTarget | undefined {
11
11
  return favoriteHover.slot ?? favoriteHover.base;
12
12
  }
13
+
@@ -1,13 +1,18 @@
1
+ import type { DatasetRef } from '@terrafirmagreg-team/sites/location';
1
2
  import type { RecipeCompactIndex } from '@terrafirmagreg-team/recipe/types';
2
3
  import { outputBoundary } from '@terrafirmagreg-team/recipe/lib/data/slot-io';
3
4
  import { loadTypeRows } from '@terrafirmagreg-team/recipe/lib/client-index';
5
+ import { createDatasetCache } from '@terrafirmagreg-team/dump/lib/dump/reader';
4
6
 
5
7
  export type FluidIoIndex = {
6
8
  inputs: Map<string, string[]>;
7
9
  outputs: Map<string, string[]>;
8
10
  };
9
11
 
10
- const cache = new Map<string, Promise<FluidIoIndex>>();
12
+ const cache = createDatasetCache(
13
+ build,
14
+ (dataset) => `${dataset.id}/${dataset.version ?? ''}`,
15
+ );
11
16
 
12
17
  function tankCategories(index: RecipeCompactIndex, role: 'input' | 'output') {
13
18
  return (index.categories ?? []).filter((cat) => {
@@ -22,7 +27,7 @@ function tankCategories(index: RecipeCompactIndex, role: 'input' | 'output') {
22
27
  }
23
28
 
24
29
  async function build(
25
- dataset: string,
30
+ dataset: DatasetRef,
26
31
  index: RecipeCompactIndex,
27
32
  ): Promise<FluidIoIndex> {
28
33
  const fluids = new Set(index.fluids ?? []);
@@ -57,16 +62,9 @@ async function build(
57
62
  }
58
63
 
59
64
  export function loadFluidIoIndex(
60
- dataset: string,
65
+ dataset: DatasetRef,
61
66
  index: RecipeCompactIndex,
62
67
  ): Promise<FluidIoIndex> {
63
- let cached = cache.get(dataset);
64
- if (!cached) {
65
- cached = build(dataset, index).catch((err) => {
66
- cache.delete(dataset);
67
- throw err;
68
- });
69
- cache.set(dataset, cached);
70
- }
71
- return cached;
68
+ return cache(dataset, index);
72
69
  }
70
+
@@ -1,4 +1,4 @@
1
- import { langString } from '@terrafirmagreg-team/game/lib/dump/assets/lang/names';
1
+ import { langString } from '@terrafirmagreg-team/dump/lib/dump/assets/lang/names';
2
2
  import type { ForgeRule, ForgeRuleAction } from '@terrafirmagreg-team/recipe/types/forge';
3
3
 
4
4
  const FORGE_STEP_LANG_PREFIX = 'tfc.enum.forgestep.';
@@ -56,3 +56,4 @@ export function forgeRulesMatch(
56
56
  );
57
57
  });
58
58
  }
59
+
@@ -1,6 +1,6 @@
1
1
  import type { Recipe } from '@terrafirmagreg-team/recipe/lib/data/dto';
2
2
  import type { ForgeRecipe } from '@terrafirmagreg-team/recipe/types/forge';
3
- import { stackIdFromRef } from '@terrafirmagreg-team/game/lib/dump/contract/ref';
3
+ import { stackIdFromRef } from '@terrafirmagreg-team/dump/lib/dump/contract/ref';
4
4
  import { parseForgeRuleTooltip } from './actions';
5
5
 
6
6
  export function toForgeRecipe(recipe: Recipe): ForgeRecipe {
@@ -48,3 +48,4 @@ export function anvilGroupRank(groupId: string): number {
48
48
  const index = ANVIL_TIER_ORDER.indexOf(last);
49
49
  return index < 0 ? ANVIL_TIER_ORDER.length : index;
50
50
  }
51
+
@@ -77,3 +77,4 @@ export function solveForgeSteps(
77
77
  }
78
78
  return null;
79
79
  }
80
+
package/src/lib/group.ts CHANGED
@@ -20,3 +20,4 @@ export function groupByCategory(
20
20
  (order.get(b.category) ?? Number.MAX_SAFE_INTEGER),
21
21
  );
22
22
  }
23
+
@@ -1,4 +1,5 @@
1
1
  'use client';
2
+ import type { DatasetRef } from '@terrafirmagreg-team/sites/location';
2
3
 
3
4
  import { useSyncExternalStore } from 'react';
4
5
  import type { RecipeCompactIndex } from '@terrafirmagreg-team/recipe/types';
@@ -6,8 +7,12 @@ import type { RecipeCompactIndex } from '@terrafirmagreg-team/recipe/types';
6
7
  const indexes = new Map<string, RecipeCompactIndex>();
7
8
  const listeners = new Set<() => void>();
8
9
 
9
- function key(dataset: string, lang: string) {
10
- return `${dataset} ${lang}`;
10
+ function refKey(dataset: DatasetRef) {
11
+ return `${dataset.id}/${dataset.version ?? ''}`;
12
+ }
13
+
14
+ function key(dataset: DatasetRef, lang: string) {
15
+ return `${refKey(dataset)} ${lang}`;
11
16
  }
12
17
 
13
18
  const namesSnapshots = new Map<
@@ -15,19 +20,19 @@ const namesSnapshots = new Map<
15
20
  Record<string, Record<string, string>>
16
21
  >();
17
22
 
18
- function rebuildNames(dataset: string) {
23
+ function rebuildNames(dataset: DatasetRef) {
19
24
  const merged: Record<string, Record<string, string>> = {};
20
25
  for (const [k, index] of indexes) {
21
- if (!k.startsWith(`${dataset} `)) continue;
26
+ if (!k.startsWith(`${refKey(dataset)} `)) continue;
22
27
  for (const [lang, names] of Object.entries(index.names ?? {})) {
23
28
  merged[lang] = { ...merged[lang], ...names };
24
29
  }
25
30
  }
26
- namesSnapshots.set(dataset, merged);
31
+ namesSnapshots.set(refKey(dataset), merged);
27
32
  }
28
33
 
29
34
  export function publishRecipeIndex(
30
- dataset: string,
35
+ dataset: DatasetRef,
31
36
  lang: string,
32
37
  index: RecipeCompactIndex,
33
38
  ) {
@@ -43,7 +48,7 @@ function subscribe(listener: () => void) {
43
48
  }
44
49
 
45
50
  export function useRecipeIndexStore(
46
- dataset: string,
51
+ dataset: DatasetRef,
47
52
  lang: string,
48
53
  ): RecipeCompactIndex | null {
49
54
  return useSyncExternalStore(
@@ -54,11 +59,12 @@ export function useRecipeIndexStore(
54
59
  }
55
60
 
56
61
  export function useRecipeIndexNames(
57
- dataset: string,
62
+ dataset: DatasetRef,
58
63
  ): Record<string, Record<string, string>> | null {
59
64
  return useSyncExternalStore(
60
65
  subscribe,
61
- () => namesSnapshots.get(dataset) ?? null,
66
+ () => namesSnapshots.get(refKey(dataset)) ?? null,
62
67
  () => null,
63
68
  );
64
69
  }
70
+