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.
- package/dist/api.d.ts +53 -5
- package/dist/api.js +42 -15
- package/dist/config.d.ts +2 -0
- package/dist/config.js +25 -11
- package/dist/get-deck.d.ts +3 -0
- package/dist/get-deck.js +64 -0
- package/dist/ide-client.d.ts +1 -0
- package/dist/ide-client.js +537 -0
- package/dist/ide.d.ts +16 -0
- package/dist/ide.js +546 -0
- package/dist/index.js +36 -41
- package/dist/init.d.ts +3 -1
- package/dist/init.js +170 -24
- package/dist/localPaths.d.ts +6 -0
- package/dist/localPaths.js +33 -0
- package/dist/login.js +1 -1
- package/dist/preview.d.ts +3 -0
- package/dist/preview.js +53 -34
- package/dist/save-deck.d.ts +2 -0
- package/dist/{push.js → save-deck.js} +66 -5
- package/dist/serve.d.ts +2 -0
- package/dist/serve.js +290 -27
- package/kits/basic-2d/.prettierrc +8 -0
- package/kits/basic-2d/CLAUDE.md +131 -0
- package/kits/basic-2d/behaviors/Camera.jsx +43 -0
- package/kits/basic-2d/behaviors/Collider.jsx +71 -0
- package/kits/basic-2d/behaviors/Drawing.jsx +139 -0
- package/kits/basic-2d/behaviors/Layout.jsx +16 -0
- package/kits/basic-2d/drawings/floor.drawing +70 -0
- package/kits/basic-2d/editors/App.jsx +152 -0
- package/kits/basic-2d/editors/CodeEditor.jsx +112 -0
- package/kits/basic-2d/editors/DrawingEditor.jsx +222 -0
- package/kits/basic-2d/editors/FileBrowser.jsx +143 -0
- package/kits/basic-2d/editors/PlayOnly.jsx +21 -0
- package/kits/basic-2d/editors/SceneEditor.jsx +1012 -0
- package/kits/basic-2d/editors/behaviorRegistry.js +24 -0
- package/kits/basic-2d/editors/editorHistory.js +52 -0
- package/kits/basic-2d/engine/ScenePlayer.jsx +83 -0
- package/kits/basic-2d/engine/SceneUI.jsx +67 -0
- package/kits/basic-2d/engine/TouchControls.jsx +136 -0
- package/kits/basic-2d/engine/autoInspector.jsx +51 -0
- package/kits/basic-2d/engine/files.js +62 -0
- package/kits/basic-2d/engine/scene.js +420 -0
- package/kits/basic-2d/engine/ui.jsx +344 -0
- package/kits/basic-2d/engine/ui.module.css +928 -0
- package/kits/basic-2d/eslint.config.js +50 -0
- package/kits/basic-2d/index.html +11 -0
- package/kits/basic-2d/main.jsx +10 -0
- package/kits/basic-2d/package-lock.json +2706 -0
- package/kits/basic-2d/package.json +41 -0
- package/kits/basic-2d/scenes/main.scene +108 -0
- package/kits/basic-2d/vite.config.js +1 -0
- package/kits/basic-2d-frozen/.prettierrc +8 -0
- package/kits/basic-2d-frozen/CLAUDE.md +131 -0
- package/kits/basic-2d-frozen/behaviors/Camera.jsx +43 -0
- package/kits/basic-2d-frozen/behaviors/Collider.jsx +71 -0
- package/kits/basic-2d-frozen/behaviors/Drawing.jsx +139 -0
- package/kits/basic-2d-frozen/behaviors/Layout.jsx +16 -0
- package/kits/basic-2d-frozen/drawings/floor.drawing +70 -0
- package/kits/basic-2d-frozen/editors/App.jsx +152 -0
- package/kits/basic-2d-frozen/editors/CodeEditor.jsx +112 -0
- package/kits/basic-2d-frozen/editors/DrawingEditor.jsx +222 -0
- package/kits/basic-2d-frozen/editors/FileBrowser.jsx +143 -0
- package/kits/basic-2d-frozen/editors/PlayOnly.jsx +21 -0
- package/kits/basic-2d-frozen/editors/SceneEditor.jsx +1012 -0
- package/kits/basic-2d-frozen/editors/behaviorRegistry.js +24 -0
- package/kits/basic-2d-frozen/editors/editorHistory.js +52 -0
- package/kits/basic-2d-frozen/engine/ScenePlayer.jsx +83 -0
- package/kits/basic-2d-frozen/engine/SceneUI.jsx +67 -0
- package/kits/basic-2d-frozen/engine/TouchControls.jsx +136 -0
- package/kits/basic-2d-frozen/engine/autoInspector.jsx +51 -0
- package/kits/basic-2d-frozen/engine/files.js +62 -0
- package/kits/basic-2d-frozen/engine/scene.js +420 -0
- package/kits/basic-2d-frozen/engine/ui.jsx +344 -0
- package/kits/basic-2d-frozen/engine/ui.module.css +928 -0
- package/kits/basic-2d-frozen/eslint.config.js +50 -0
- package/kits/basic-2d-frozen/index.html +11 -0
- package/kits/basic-2d-frozen/main.jsx +10 -0
- package/kits/basic-2d-frozen/package-lock.json +2706 -0
- package/kits/basic-2d-frozen/package.json +41 -0
- package/kits/basic-2d-frozen/scenes/main.scene +108 -0
- package/kits/basic-2d-frozen/vite.config.js +1 -0
- package/kits/rpg-2d/.prettierrc +8 -0
- package/kits/rpg-2d/behaviors/Camera.tsx +52 -0
- package/kits/rpg-2d/behaviors/Collider.tsx +98 -0
- package/kits/rpg-2d/behaviors/Dialog.tsx +184 -0
- package/kits/rpg-2d/behaviors/Drawing.tsx +161 -0
- package/kits/rpg-2d/behaviors/Friend.tsx +45 -0
- package/kits/rpg-2d/behaviors/Layout.tsx +29 -0
- package/kits/rpg-2d/behaviors/PlayerController.tsx +255 -0
- package/kits/rpg-2d/behaviors/Portal.tsx +60 -0
- package/kits/rpg-2d/behaviors/QuestLog.tsx +90 -0
- package/kits/rpg-2d/behaviors/SaveMenu.tsx +123 -0
- package/kits/rpg-2d/behaviors/Tilemap.tsx +90 -0
- package/kits/rpg-2d/drawings/bld-home.drawing +8136 -0
- package/kits/rpg-2d/drawings/env-crate.drawing +509 -0
- package/kits/rpg-2d/drawings/env-fence.drawing +536 -0
- package/kits/rpg-2d/drawings/env-flower-bed.drawing +607 -0
- package/kits/rpg-2d/drawings/env-fountain.drawing +2622 -0
- package/kits/rpg-2d/drawings/env-hedge.drawing +601 -0
- package/kits/rpg-2d/drawings/env-house-blue.drawing +1 -0
- package/kits/rpg-2d/drawings/env-house-green.drawing +1 -0
- package/kits/rpg-2d/drawings/env-tree-oak.drawing +1540 -0
- package/kits/rpg-2d/drawings/env-tree-pine.drawing +1315 -0
- package/kits/rpg-2d/drawings/floor.drawing +70 -0
- package/kits/rpg-2d/drawings/fx-sparkle.drawing +926 -0
- package/kits/rpg-2d/drawings/npc-juno-idle-down.drawing +1099 -0
- package/kits/rpg-2d/drawings/npc-juno-walk-down.drawing +4177 -0
- package/kits/rpg-2d/drawings/npc-opal-idle-down.drawing +1099 -0
- package/kits/rpg-2d/drawings/npc-opal-walk-down.drawing +4177 -0
- package/kits/rpg-2d/drawings/player-idle-down.drawing +1070 -0
- package/kits/rpg-2d/drawings/player-idle-left.drawing +1070 -0
- package/kits/rpg-2d/drawings/player-idle-right.drawing +1070 -0
- package/kits/rpg-2d/drawings/player-idle-up.drawing +1070 -0
- package/kits/rpg-2d/drawings/player-walk-down.drawing +4148 -0
- package/kits/rpg-2d/drawings/player-walk-left.drawing +4148 -0
- package/kits/rpg-2d/drawings/player-walk-right.drawing +4148 -0
- package/kits/rpg-2d/drawings/player-walk-up.drawing +4148 -0
- package/kits/rpg-2d/editors/App.tsx +163 -0
- package/kits/rpg-2d/editors/CodeEditor.tsx +120 -0
- package/kits/rpg-2d/editors/DrawingEditor.tsx +278 -0
- package/kits/rpg-2d/editors/FileBrowser.tsx +191 -0
- package/kits/rpg-2d/editors/PlayOnly.tsx +26 -0
- package/kits/rpg-2d/editors/SceneEditor.tsx +1093 -0
- package/kits/rpg-2d/editors/behaviorRegistry.ts +33 -0
- package/kits/rpg-2d/editors/editorHistory.ts +75 -0
- package/kits/rpg-2d/editors/editorProps.ts +10 -0
- package/kits/rpg-2d/engine/ScenePlayer.tsx +130 -0
- package/kits/rpg-2d/engine/SceneUI.tsx +74 -0
- package/kits/rpg-2d/engine/TouchControls.tsx +157 -0
- package/kits/rpg-2d/engine/autoInspector.tsx +111 -0
- package/kits/rpg-2d/engine/drawing.ts +81 -0
- package/kits/rpg-2d/engine/files.ts +215 -0
- package/kits/rpg-2d/engine/scene.ts +484 -0
- package/kits/rpg-2d/engine/ui.module.css +928 -0
- package/kits/rpg-2d/engine/ui.tsx +483 -0
- package/kits/rpg-2d/eslint.config.js +46 -0
- package/kits/rpg-2d/index.html +11 -0
- package/kits/rpg-2d/main.tsx +14 -0
- package/kits/rpg-2d/package-lock.json +3149 -0
- package/kits/rpg-2d/package.json +46 -0
- package/kits/rpg-2d/scenes/main.scene +203 -0
- package/kits/rpg-2d/tsconfig.json +17 -0
- package/kits/rpg-2d/vite-env.d.ts +7 -0
- package/kits/rpg-2d/vite.config.js +1 -0
- package/package.json +27 -5
- package/AGENTS.md +0 -25
- package/dist/push.d.ts +0 -1
- package/src/api.ts +0 -160
- package/src/bundle.ts +0 -28
- package/src/config.ts +0 -36
- package/src/index.ts +0 -143
- package/src/init.ts +0 -71
- package/src/login.ts +0 -24
- package/src/preview.ts +0 -94
- package/src/push.ts +0 -118
- package/src/serve.ts +0 -134
- 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
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
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<
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
|
|
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
|
-
|
|
86
|
-
|
|
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
|
|
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
|
|
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
|
|
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
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
+
}
|
package/dist/get-deck.js
ADDED
|
@@ -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 {};
|