castle-web-cli 0.4.1 → 0.4.2

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 (158) hide show
  1. package/dist/api.d.ts +53 -5
  2. package/dist/api.js +42 -15
  3. package/dist/config.d.ts +2 -0
  4. package/dist/config.js +25 -11
  5. package/dist/get-deck.d.ts +3 -0
  6. package/dist/get-deck.js +64 -0
  7. package/dist/ide-client.d.ts +1 -0
  8. package/dist/ide-client.js +537 -0
  9. package/dist/ide.d.ts +16 -0
  10. package/dist/ide.js +546 -0
  11. package/dist/index.js +36 -41
  12. package/dist/init.d.ts +3 -1
  13. package/dist/init.js +170 -24
  14. package/dist/localPaths.d.ts +6 -0
  15. package/dist/localPaths.js +33 -0
  16. package/dist/login.js +1 -1
  17. package/dist/preview.d.ts +3 -0
  18. package/dist/preview.js +53 -34
  19. package/dist/save-deck.d.ts +2 -0
  20. package/dist/{push.js → save-deck.js} +66 -5
  21. package/dist/serve.d.ts +2 -0
  22. package/dist/serve.js +290 -27
  23. package/kits/basic-2d/.prettierrc +8 -0
  24. package/kits/basic-2d/CLAUDE.md +131 -0
  25. package/kits/basic-2d/behaviors/Camera.jsx +43 -0
  26. package/kits/basic-2d/behaviors/Collider.jsx +71 -0
  27. package/kits/basic-2d/behaviors/Drawing.jsx +139 -0
  28. package/kits/basic-2d/behaviors/Layout.jsx +16 -0
  29. package/kits/basic-2d/drawings/floor.drawing +70 -0
  30. package/kits/basic-2d/editors/App.jsx +152 -0
  31. package/kits/basic-2d/editors/CodeEditor.jsx +112 -0
  32. package/kits/basic-2d/editors/DrawingEditor.jsx +222 -0
  33. package/kits/basic-2d/editors/FileBrowser.jsx +143 -0
  34. package/kits/basic-2d/editors/PlayOnly.jsx +21 -0
  35. package/kits/basic-2d/editors/SceneEditor.jsx +1012 -0
  36. package/kits/basic-2d/editors/behaviorRegistry.js +24 -0
  37. package/kits/basic-2d/editors/editorHistory.js +52 -0
  38. package/kits/basic-2d/engine/ScenePlayer.jsx +83 -0
  39. package/kits/basic-2d/engine/SceneUI.jsx +67 -0
  40. package/kits/basic-2d/engine/TouchControls.jsx +136 -0
  41. package/kits/basic-2d/engine/autoInspector.jsx +51 -0
  42. package/kits/basic-2d/engine/files.js +62 -0
  43. package/kits/basic-2d/engine/scene.js +420 -0
  44. package/kits/basic-2d/engine/ui.jsx +344 -0
  45. package/kits/basic-2d/engine/ui.module.css +928 -0
  46. package/kits/basic-2d/eslint.config.js +50 -0
  47. package/kits/basic-2d/index.html +11 -0
  48. package/kits/basic-2d/main.jsx +10 -0
  49. package/kits/basic-2d/package-lock.json +2706 -0
  50. package/kits/basic-2d/package.json +41 -0
  51. package/kits/basic-2d/scenes/main.scene +108 -0
  52. package/kits/basic-2d/vite.config.js +1 -0
  53. package/kits/basic-2d-frozen/.prettierrc +8 -0
  54. package/kits/basic-2d-frozen/CLAUDE.md +131 -0
  55. package/kits/basic-2d-frozen/behaviors/Camera.jsx +43 -0
  56. package/kits/basic-2d-frozen/behaviors/Collider.jsx +71 -0
  57. package/kits/basic-2d-frozen/behaviors/Drawing.jsx +139 -0
  58. package/kits/basic-2d-frozen/behaviors/Layout.jsx +16 -0
  59. package/kits/basic-2d-frozen/drawings/floor.drawing +70 -0
  60. package/kits/basic-2d-frozen/editors/App.jsx +152 -0
  61. package/kits/basic-2d-frozen/editors/CodeEditor.jsx +112 -0
  62. package/kits/basic-2d-frozen/editors/DrawingEditor.jsx +222 -0
  63. package/kits/basic-2d-frozen/editors/FileBrowser.jsx +143 -0
  64. package/kits/basic-2d-frozen/editors/PlayOnly.jsx +21 -0
  65. package/kits/basic-2d-frozen/editors/SceneEditor.jsx +1012 -0
  66. package/kits/basic-2d-frozen/editors/behaviorRegistry.js +24 -0
  67. package/kits/basic-2d-frozen/editors/editorHistory.js +52 -0
  68. package/kits/basic-2d-frozen/engine/ScenePlayer.jsx +83 -0
  69. package/kits/basic-2d-frozen/engine/SceneUI.jsx +67 -0
  70. package/kits/basic-2d-frozen/engine/TouchControls.jsx +136 -0
  71. package/kits/basic-2d-frozen/engine/autoInspector.jsx +51 -0
  72. package/kits/basic-2d-frozen/engine/files.js +62 -0
  73. package/kits/basic-2d-frozen/engine/scene.js +420 -0
  74. package/kits/basic-2d-frozen/engine/ui.jsx +344 -0
  75. package/kits/basic-2d-frozen/engine/ui.module.css +928 -0
  76. package/kits/basic-2d-frozen/eslint.config.js +50 -0
  77. package/kits/basic-2d-frozen/index.html +11 -0
  78. package/kits/basic-2d-frozen/main.jsx +10 -0
  79. package/kits/basic-2d-frozen/package-lock.json +2706 -0
  80. package/kits/basic-2d-frozen/package.json +41 -0
  81. package/kits/basic-2d-frozen/scenes/main.scene +108 -0
  82. package/kits/basic-2d-frozen/vite.config.js +1 -0
  83. package/kits/rpg-2d/.prettierrc +8 -0
  84. package/kits/rpg-2d/behaviors/Camera.tsx +52 -0
  85. package/kits/rpg-2d/behaviors/Collider.tsx +98 -0
  86. package/kits/rpg-2d/behaviors/Dialog.tsx +184 -0
  87. package/kits/rpg-2d/behaviors/Drawing.tsx +161 -0
  88. package/kits/rpg-2d/behaviors/Friend.tsx +45 -0
  89. package/kits/rpg-2d/behaviors/Layout.tsx +29 -0
  90. package/kits/rpg-2d/behaviors/PlayerController.tsx +255 -0
  91. package/kits/rpg-2d/behaviors/Portal.tsx +60 -0
  92. package/kits/rpg-2d/behaviors/QuestLog.tsx +90 -0
  93. package/kits/rpg-2d/behaviors/SaveMenu.tsx +123 -0
  94. package/kits/rpg-2d/behaviors/Tilemap.tsx +90 -0
  95. package/kits/rpg-2d/drawings/bld-home.drawing +8136 -0
  96. package/kits/rpg-2d/drawings/env-crate.drawing +509 -0
  97. package/kits/rpg-2d/drawings/env-fence.drawing +536 -0
  98. package/kits/rpg-2d/drawings/env-flower-bed.drawing +607 -0
  99. package/kits/rpg-2d/drawings/env-fountain.drawing +2622 -0
  100. package/kits/rpg-2d/drawings/env-hedge.drawing +601 -0
  101. package/kits/rpg-2d/drawings/env-house-blue.drawing +1 -0
  102. package/kits/rpg-2d/drawings/env-house-green.drawing +1 -0
  103. package/kits/rpg-2d/drawings/env-tree-oak.drawing +1540 -0
  104. package/kits/rpg-2d/drawings/env-tree-pine.drawing +1315 -0
  105. package/kits/rpg-2d/drawings/floor.drawing +70 -0
  106. package/kits/rpg-2d/drawings/fx-sparkle.drawing +926 -0
  107. package/kits/rpg-2d/drawings/npc-juno-idle-down.drawing +1099 -0
  108. package/kits/rpg-2d/drawings/npc-juno-walk-down.drawing +4177 -0
  109. package/kits/rpg-2d/drawings/npc-opal-idle-down.drawing +1099 -0
  110. package/kits/rpg-2d/drawings/npc-opal-walk-down.drawing +4177 -0
  111. package/kits/rpg-2d/drawings/player-idle-down.drawing +1070 -0
  112. package/kits/rpg-2d/drawings/player-idle-left.drawing +1070 -0
  113. package/kits/rpg-2d/drawings/player-idle-right.drawing +1070 -0
  114. package/kits/rpg-2d/drawings/player-idle-up.drawing +1070 -0
  115. package/kits/rpg-2d/drawings/player-walk-down.drawing +4148 -0
  116. package/kits/rpg-2d/drawings/player-walk-left.drawing +4148 -0
  117. package/kits/rpg-2d/drawings/player-walk-right.drawing +4148 -0
  118. package/kits/rpg-2d/drawings/player-walk-up.drawing +4148 -0
  119. package/kits/rpg-2d/editors/App.tsx +163 -0
  120. package/kits/rpg-2d/editors/CodeEditor.tsx +120 -0
  121. package/kits/rpg-2d/editors/DrawingEditor.tsx +278 -0
  122. package/kits/rpg-2d/editors/FileBrowser.tsx +191 -0
  123. package/kits/rpg-2d/editors/PlayOnly.tsx +26 -0
  124. package/kits/rpg-2d/editors/SceneEditor.tsx +1093 -0
  125. package/kits/rpg-2d/editors/behaviorRegistry.ts +33 -0
  126. package/kits/rpg-2d/editors/editorHistory.ts +75 -0
  127. package/kits/rpg-2d/editors/editorProps.ts +10 -0
  128. package/kits/rpg-2d/engine/ScenePlayer.tsx +130 -0
  129. package/kits/rpg-2d/engine/SceneUI.tsx +74 -0
  130. package/kits/rpg-2d/engine/TouchControls.tsx +157 -0
  131. package/kits/rpg-2d/engine/autoInspector.tsx +111 -0
  132. package/kits/rpg-2d/engine/drawing.ts +81 -0
  133. package/kits/rpg-2d/engine/files.ts +215 -0
  134. package/kits/rpg-2d/engine/scene.ts +484 -0
  135. package/kits/rpg-2d/engine/ui.module.css +928 -0
  136. package/kits/rpg-2d/engine/ui.tsx +483 -0
  137. package/kits/rpg-2d/eslint.config.js +46 -0
  138. package/kits/rpg-2d/index.html +11 -0
  139. package/kits/rpg-2d/main.tsx +14 -0
  140. package/kits/rpg-2d/package-lock.json +3149 -0
  141. package/kits/rpg-2d/package.json +46 -0
  142. package/kits/rpg-2d/scenes/main.scene +203 -0
  143. package/kits/rpg-2d/tsconfig.json +17 -0
  144. package/kits/rpg-2d/vite-env.d.ts +7 -0
  145. package/kits/rpg-2d/vite.config.js +1 -0
  146. package/package.json +27 -5
  147. package/AGENTS.md +0 -25
  148. package/dist/push.d.ts +0 -1
  149. package/src/api.ts +0 -160
  150. package/src/bundle.ts +0 -28
  151. package/src/config.ts +0 -36
  152. package/src/index.ts +0 -143
  153. package/src/init.ts +0 -71
  154. package/src/login.ts +0 -24
  155. package/src/preview.ts +0 -94
  156. package/src/push.ts +0 -118
  157. package/src/serve.ts +0 -134
  158. package/tsconfig.json +0 -13
package/dist/api.d.ts CHANGED
@@ -2,9 +2,33 @@ export declare function startCLILogin(): Promise<{
2
2
  pollToken: string;
3
3
  url: string;
4
4
  }>;
5
- export declare function pollForCLILogin(pollToken: string): Promise<any>;
6
- export declare function me(): Promise<any>;
7
- export declare function myDecks(): Promise<any[]>;
5
+ export interface MeResult {
6
+ userId: string;
7
+ username: string;
8
+ token: string;
9
+ isAnonymous: boolean;
10
+ }
11
+ export declare function pollForCLILogin(pollToken: string): Promise<MeResult | null>;
12
+ export interface MeProfile {
13
+ userId: string;
14
+ username: string;
15
+ isAnonymous: boolean;
16
+ photo?: {
17
+ url?: string;
18
+ } | null;
19
+ photoFrame?: {
20
+ frameUrl?: string;
21
+ } | null;
22
+ }
23
+ export declare function me(): Promise<MeProfile | null>;
24
+ export interface DeckSummary {
25
+ deckId: string;
26
+ title: string;
27
+ initialCard?: {
28
+ cardId: string;
29
+ } | null;
30
+ }
31
+ export declare function myDecks(): Promise<DeckSummary[]>;
8
32
  export declare function updateCardAndDeckV2(deck: Record<string, unknown>, card: Record<string, unknown>): Promise<{
9
33
  deckId: string;
10
34
  cardId: string;
@@ -13,13 +37,37 @@ export declare function createDeck(deck: Record<string, unknown>, card: Record<s
13
37
  deckId: string;
14
38
  cardId: string;
15
39
  }>;
16
- export declare function createSceneDataUploadConfig(cardIds: string[]): Promise<any[]>;
40
+ export interface SceneDataUploadConfig {
41
+ cardId: string;
42
+ uploadId: string;
43
+ postUrl: string;
44
+ postFields: Record<string, string>;
45
+ }
46
+ export declare function createSceneDataUploadConfig(cardIds: string[]): Promise<SceneDataUploadConfig[]>;
47
+ export interface UploadedSceneData {
48
+ cardId: string;
49
+ sceneDataUrl: string;
50
+ }
17
51
  export declare function uploadSceneData(cards: Array<{
18
52
  cardId: string;
19
53
  uploadId: string;
20
- }>): Promise<any[]>;
54
+ }>): Promise<UploadedSceneData[]>;
21
55
  export declare function uploadBase64(base64: string, filename: string): Promise<{
22
56
  fileId: string;
23
57
  url: string;
24
58
  }>;
25
59
  export declare function updateCardCustomBackgroundImage(cardId: string, backgroundImageFileId: string): Promise<void>;
60
+ export interface WebDeckSourceUploadConfig {
61
+ deckId: string;
62
+ uploadId: string;
63
+ postUrl: string;
64
+ postFields: Record<string, string>;
65
+ }
66
+ export declare function createWebDeckSourceUploadConfig(deckId: string): Promise<WebDeckSourceUploadConfig>;
67
+ export interface WebDeckSource {
68
+ deckId: string;
69
+ archiveUrl: string;
70
+ updatedAt: string;
71
+ }
72
+ export declare function webDeckSource(deckId: string): Promise<WebDeckSource | null>;
73
+ export declare function saveWebDeckSource(deckId: string, uploadId: string): Promise<WebDeckSource>;
package/dist/api.js CHANGED
@@ -25,10 +25,13 @@ function handleAPIError(data) {
25
25
  throw err;
26
26
  }
27
27
  }
28
+ function pickData(data, key) {
29
+ return (data.data?.[key] ?? null);
30
+ }
28
31
  export async function startCLILogin() {
29
32
  const data = await graphql(`mutation { startCLILogin { pollToken url } }`);
30
33
  handleAPIError(data);
31
- return data.data.startCLILogin;
34
+ return pickData(data, 'startCLILogin');
32
35
  }
33
36
  export async function pollForCLILogin(pollToken) {
34
37
  const data = await graphql(`query($pollToken: String!) {
@@ -37,12 +40,12 @@ export async function pollForCLILogin(pollToken) {
37
40
  }
38
41
  }`, { pollToken });
39
42
  handleAPIError(data);
40
- return data.data?.pollForCLILogin ?? null;
43
+ return pickData(data, 'pollForCLILogin');
41
44
  }
42
45
  export async function me() {
43
46
  try {
44
47
  const data = await graphql(`query { me { userId username isAnonymous photo { url } photoFrame { frameUrl } } }`);
45
- return data.data?.me ?? null;
48
+ return pickData(data, 'me');
46
49
  }
47
50
  catch {
48
51
  return null;
@@ -59,7 +62,8 @@ export async function myDecks() {
59
62
  }
60
63
  }`);
61
64
  handleAPIError(data);
62
- return data.data?.me?.decks ?? [];
65
+ const meData = data.data?.me;
66
+ return meData?.decks ?? [];
63
67
  }
64
68
  export async function updateCardAndDeckV2(deck, card) {
65
69
  const data = await graphql(`mutation($deck: DeckInput!, $card: CardInput!) {
@@ -69,10 +73,8 @@ export async function updateCardAndDeckV2(deck, card) {
69
73
  }
70
74
  }`, { deck, card });
71
75
  handleAPIError(data);
72
- return {
73
- deckId: data.data.updateCardAndDeckV2.deck.deckId,
74
- cardId: data.data.updateCardAndDeckV2.card.cardId,
75
- };
76
+ const result = data.data?.updateCardAndDeckV2;
77
+ return { deckId: result.deck.deckId, cardId: result.card.cardId };
76
78
  }
77
79
  export async function createDeck(deck, card) {
78
80
  const data = await graphql(`mutation($deck: DeckInput!, $card: CardInput!) {
@@ -82,10 +84,8 @@ export async function createDeck(deck, card) {
82
84
  }
83
85
  }`, { deck, card });
84
86
  handleAPIError(data);
85
- return {
86
- deckId: data.data.createDeck.deckId,
87
- cardId: data.data.createDeck.initialCard.cardId,
88
- };
87
+ const result = data.data?.createDeck;
88
+ return { deckId: result.deckId, cardId: result.initialCard.cardId };
89
89
  }
90
90
  export async function createSceneDataUploadConfig(cardIds) {
91
91
  const data = await graphql(`mutation($cardIds: [ID!]!) {
@@ -94,14 +94,14 @@ export async function createSceneDataUploadConfig(cardIds) {
94
94
  }
95
95
  }`, { cardIds });
96
96
  handleAPIError(data);
97
- return data.data.createSceneDataUploadConfig;
97
+ return pickData(data, 'createSceneDataUploadConfig');
98
98
  }
99
99
  export async function uploadSceneData(cards) {
100
100
  const data = await graphql(`mutation($cards: [CardSceneDataInput!]!) {
101
101
  uploadSceneData(cards: $cards) { cardId sceneDataUrl }
102
102
  }`, { cards });
103
103
  handleAPIError(data);
104
- return data.data.uploadSceneData;
104
+ return pickData(data, 'uploadSceneData');
105
105
  }
106
106
  export async function uploadBase64(base64, filename) {
107
107
  const data = await graphql(`mutation($data: String!, $filename: String, $mimetype: String) {
@@ -110,7 +110,7 @@ export async function uploadBase64(base64, filename) {
110
110
  }
111
111
  }`, { data: base64, filename, mimetype: 'image/png' });
112
112
  handleAPIError(data);
113
- return data.data.uploadBase64;
113
+ return pickData(data, 'uploadBase64');
114
114
  }
115
115
  export async function updateCardCustomBackgroundImage(cardId, backgroundImageFileId) {
116
116
  const data = await graphql(`mutation($cardId: ID!, $backgroundImageFileId: ID) {
@@ -118,3 +118,30 @@ export async function updateCardCustomBackgroundImage(cardId, backgroundImageFil
118
118
  }`, { cardId, backgroundImageFileId });
119
119
  handleAPIError(data);
120
120
  }
121
+ export async function createWebDeckSourceUploadConfig(deckId) {
122
+ const data = await graphql(`mutation($deckId: ID!) {
123
+ createWebDeckSourceUploadConfig(deckId: $deckId) {
124
+ deckId uploadId postUrl postFields
125
+ }
126
+ }`, { deckId });
127
+ handleAPIError(data);
128
+ return pickData(data, 'createWebDeckSourceUploadConfig');
129
+ }
130
+ export async function webDeckSource(deckId) {
131
+ const data = await graphql(`query($deckId: ID!) {
132
+ webDeckSource(deckId: $deckId) {
133
+ deckId archiveUrl updatedAt
134
+ }
135
+ }`, { deckId });
136
+ handleAPIError(data);
137
+ return pickData(data, 'webDeckSource');
138
+ }
139
+ export async function saveWebDeckSource(deckId, uploadId) {
140
+ const data = await graphql(`mutation($deckId: ID!, $uploadId: ID!) {
141
+ saveWebDeckSource(deckId: $deckId, uploadId: $uploadId) {
142
+ deckId archiveUrl updatedAt
143
+ }
144
+ }`, { deckId, uploadId });
145
+ handleAPIError(data);
146
+ return pickData(data, 'saveWebDeckSource');
147
+ }
package/dist/config.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export declare function getToken(): string | null;
2
+ export declare function getUserId(): string | null;
2
3
  export declare function setToken(token: string | null): void;
4
+ export declare function setAuth(token: string, userId: string): void;
package/dist/config.js CHANGED
@@ -12,23 +12,37 @@ function readConfigFile(filename) {
12
12
  return JSON.parse(fs.readFileSync(configFilePath, 'utf-8'));
13
13
  }
14
14
  }
15
- catch { }
15
+ catch {
16
+ // missing / unreadable / malformed config is treated as no config
17
+ }
16
18
  return null;
17
19
  }
18
- export function getToken() {
19
- const config = readConfigFile('config.json');
20
- return config ? config.token : null;
21
- }
22
- export function setToken(token) {
20
+ function writeConfig(updates) {
23
21
  const configDir = getConfigDir();
24
22
  fs.mkdirSync(configDir, { recursive: true });
25
23
  const existing = readConfigFile('config.json') ?? {};
26
- if (token === null) {
27
- delete existing.token;
28
- }
29
- else {
30
- existing.token = token;
24
+ for (const [k, v] of Object.entries(updates)) {
25
+ if (v === null) {
26
+ delete existing[k];
27
+ }
28
+ else {
29
+ existing[k] = v;
30
+ }
31
31
  }
32
32
  const configFilePath = path.join(configDir, 'config.json');
33
33
  fs.writeFileSync(configFilePath, JSON.stringify(existing, null, 2), 'utf-8');
34
34
  }
35
+ export function getToken() {
36
+ const c = readConfigFile('config.json');
37
+ return c && typeof c.token === 'string' ? c.token : null;
38
+ }
39
+ export function getUserId() {
40
+ const c = readConfigFile('config.json');
41
+ return c && typeof c.userId === 'string' ? c.userId : null;
42
+ }
43
+ export function setToken(token) {
44
+ writeConfig({ token });
45
+ }
46
+ export function setAuth(token, userId) {
47
+ writeConfig({ token, userId });
48
+ }
@@ -0,0 +1,3 @@
1
+ export declare function getDeck(dir: string, options?: {
2
+ deckId?: string;
3
+ }): Promise<void>;
@@ -0,0 +1,64 @@
1
+ import * as fs from 'fs';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+ import { spawn } from 'child_process';
5
+ import { nanoid } from 'nanoid';
6
+ import * as api from './api.js';
7
+ function readCastleJson(dir) {
8
+ const p = path.join(dir, 'castle.json');
9
+ if (!fs.existsSync(p))
10
+ return null;
11
+ return JSON.parse(fs.readFileSync(p, 'utf-8'));
12
+ }
13
+ function extractTarball(archivePath, targetDir) {
14
+ return new Promise((resolve, reject) => {
15
+ const child = spawn('tar', ['-xzf', archivePath, '-C', targetDir], {
16
+ stdio: ['ignore', 'inherit', 'pipe'],
17
+ });
18
+ let stderr = '';
19
+ child.stderr?.on('data', (chunk) => { stderr += chunk.toString(); });
20
+ child.on('error', reject);
21
+ child.on('close', (code) => {
22
+ if (code !== 0) {
23
+ reject(new Error(`tar exited with code ${code}: ${stderr}`));
24
+ return;
25
+ }
26
+ resolve();
27
+ });
28
+ });
29
+ }
30
+ export async function getDeck(dir, options = {}) {
31
+ const targetDir = path.resolve(dir);
32
+ const existing = readCastleJson(targetDir);
33
+ const deckId = options.deckId ?? existing?.deckId;
34
+ if (!deckId) {
35
+ console.error(`No deckId. Either pass --deck-id <id> or run from a directory whose castle.json has one.`);
36
+ process.exit(1);
37
+ }
38
+ const source = await api.webDeckSource(deckId);
39
+ if (!source) {
40
+ console.error(`No source archive on server for deck ${deckId}. Run \`castle-web save-deck\` first.`);
41
+ process.exit(1);
42
+ }
43
+ console.log(`Fetching ${source.archiveUrl}`);
44
+ const res = await fetch(source.archiveUrl, { signal: AbortSignal.timeout(60000) });
45
+ if (!res.ok) {
46
+ throw new Error(`Archive fetch failed: HTTP ${res.status}`);
47
+ }
48
+ const buf = Buffer.from(await res.arrayBuffer());
49
+ const sizeKB = buf.length / 1024;
50
+ console.log(`Archive: ${sizeKB.toFixed(1)}KB (updated ${source.updatedAt})`);
51
+ fs.mkdirSync(targetDir, { recursive: true });
52
+ const tmpFile = path.join(os.tmpdir(), `castle-get-${nanoid(8)}.tar.gz`);
53
+ fs.writeFileSync(tmpFile, buf);
54
+ try {
55
+ await extractTarball(tmpFile, targetDir);
56
+ }
57
+ finally {
58
+ try {
59
+ fs.unlinkSync(tmpFile);
60
+ }
61
+ catch { /* nothing to clean */ }
62
+ }
63
+ console.log(`Extracted to ${targetDir}`);
64
+ }
@@ -0,0 +1 @@
1
+ export {};