flingit 0.0.1
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/README.md +84 -0
- package/dist/cli/commands/db.d.ts +9 -0
- package/dist/cli/commands/db.d.ts.map +1 -0
- package/dist/cli/commands/db.js +215 -0
- package/dist/cli/commands/db.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +6 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +145 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/feedback.d.ts +6 -0
- package/dist/cli/commands/feedback.d.ts.map +1 -0
- package/dist/cli/commands/feedback.js +116 -0
- package/dist/cli/commands/feedback.js.map +1 -0
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +161 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/launch.d.ts +12 -0
- package/dist/cli/commands/launch.d.ts.map +1 -0
- package/dist/cli/commands/launch.js +176 -0
- package/dist/cli/commands/launch.js.map +1 -0
- package/dist/cli/commands/login.d.ts +6 -0
- package/dist/cli/commands/login.d.ts.map +1 -0
- package/dist/cli/commands/login.js +90 -0
- package/dist/cli/commands/login.js.map +1 -0
- package/dist/cli/commands/logout.d.ts +6 -0
- package/dist/cli/commands/logout.d.ts.map +1 -0
- package/dist/cli/commands/logout.js +32 -0
- package/dist/cli/commands/logout.js.map +1 -0
- package/dist/cli/commands/logs.d.ts +12 -0
- package/dist/cli/commands/logs.d.ts.map +1 -0
- package/dist/cli/commands/logs.js +261 -0
- package/dist/cli/commands/logs.js.map +1 -0
- package/dist/cli/commands/onboard.d.ts +22 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -0
- package/dist/cli/commands/onboard.js +244 -0
- package/dist/cli/commands/onboard.js.map +1 -0
- package/dist/cli/commands/project.d.ts +6 -0
- package/dist/cli/commands/project.d.ts.map +1 -0
- package/dist/cli/commands/project.js +142 -0
- package/dist/cli/commands/project.js.map +1 -0
- package/dist/cli/commands/push.d.ts +6 -0
- package/dist/cli/commands/push.d.ts.map +1 -0
- package/dist/cli/commands/push.js +351 -0
- package/dist/cli/commands/push.js.map +1 -0
- package/dist/cli/commands/register.d.ts +6 -0
- package/dist/cli/commands/register.d.ts.map +1 -0
- package/dist/cli/commands/register.js +115 -0
- package/dist/cli/commands/register.js.map +1 -0
- package/dist/cli/commands/secret.d.ts +11 -0
- package/dist/cli/commands/secret.d.ts.map +1 -0
- package/dist/cli/commands/secret.js +124 -0
- package/dist/cli/commands/secret.js.map +1 -0
- package/dist/cli/commands/whoami.d.ts +6 -0
- package/dist/cli/commands/whoami.d.ts.map +1 -0
- package/dist/cli/commands/whoami.js +54 -0
- package/dist/cli/commands/whoami.js.map +1 -0
- package/dist/cli/deploy/assets.d.ts +73 -0
- package/dist/cli/deploy/assets.d.ts.map +1 -0
- package/dist/cli/deploy/assets.js +167 -0
- package/dist/cli/deploy/assets.js.map +1 -0
- package/dist/cli/deploy/base64-stream.d.ts +16 -0
- package/dist/cli/deploy/base64-stream.d.ts.map +1 -0
- package/dist/cli/deploy/base64-stream.js +44 -0
- package/dist/cli/deploy/base64-stream.js.map +1 -0
- package/dist/cli/deploy/bucket-stream.d.ts +18 -0
- package/dist/cli/deploy/bucket-stream.d.ts.map +1 -0
- package/dist/cli/deploy/bucket-stream.js +63 -0
- package/dist/cli/deploy/bucket-stream.js.map +1 -0
- package/dist/cli/deploy/bundler.d.ts +22 -0
- package/dist/cli/deploy/bundler.d.ts.map +1 -0
- package/dist/cli/deploy/bundler.js +131 -0
- package/dist/cli/deploy/bundler.js.map +1 -0
- package/dist/cli/deploy/worker-entry.d.ts +14 -0
- package/dist/cli/deploy/worker-entry.d.ts.map +1 -0
- package/dist/cli/deploy/worker-entry.js +60 -0
- package/dist/cli/deploy/worker-entry.js.map +1 -0
- package/dist/cli/deploy/wrangler-config.d.ts +20 -0
- package/dist/cli/deploy/wrangler-config.d.ts.map +1 -0
- package/dist/cli/deploy/wrangler-config.js +54 -0
- package/dist/cli/deploy/wrangler-config.js.map +1 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +72 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/config.d.ts +39 -0
- package/dist/cli/utils/config.d.ts.map +1 -0
- package/dist/cli/utils/config.js +105 -0
- package/dist/cli/utils/config.js.map +1 -0
- package/dist/cli/utils/duration.d.ts +21 -0
- package/dist/cli/utils/duration.d.ts.map +1 -0
- package/dist/cli/utils/duration.js +44 -0
- package/dist/cli/utils/duration.js.map +1 -0
- package/dist/cli/utils/environment.d.ts +17 -0
- package/dist/cli/utils/environment.d.ts.map +1 -0
- package/dist/cli/utils/environment.js +27 -0
- package/dist/cli/utils/environment.js.map +1 -0
- package/dist/cli/utils/project.d.ts +24 -0
- package/dist/cli/utils/project.d.ts.map +1 -0
- package/dist/cli/utils/project.js +47 -0
- package/dist/cli/utils/project.js.map +1 -0
- package/dist/cli/utils/registry.d.ts +34 -0
- package/dist/cli/utils/registry.d.ts.map +1 -0
- package/dist/cli/utils/registry.js +94 -0
- package/dist/cli/utils/registry.js.map +1 -0
- package/dist/cli/utils/token.d.ts +12 -0
- package/dist/cli/utils/token.d.ts.map +1 -0
- package/dist/cli/utils/token.js +27 -0
- package/dist/cli/utils/token.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/cron.d.ts +50 -0
- package/dist/runtime/cron.d.ts.map +1 -0
- package/dist/runtime/cron.js +80 -0
- package/dist/runtime/cron.js.map +1 -0
- package/dist/runtime/db.d.ts +93 -0
- package/dist/runtime/db.d.ts.map +1 -0
- package/dist/runtime/db.js +137 -0
- package/dist/runtime/db.js.map +1 -0
- package/dist/runtime/http.d.ts +33 -0
- package/dist/runtime/http.d.ts.map +1 -0
- package/dist/runtime/http.js +36 -0
- package/dist/runtime/http.js.map +1 -0
- package/dist/runtime/log.d.ts +90 -0
- package/dist/runtime/log.d.ts.map +1 -0
- package/dist/runtime/log.js +211 -0
- package/dist/runtime/log.js.map +1 -0
- package/dist/runtime/migrate.d.ts +54 -0
- package/dist/runtime/migrate.d.ts.map +1 -0
- package/dist/runtime/migrate.js +130 -0
- package/dist/runtime/migrate.js.map +1 -0
- package/dist/runtime/secrets.d.ts +36 -0
- package/dist/runtime/secrets.d.ts.map +1 -0
- package/dist/runtime/secrets.js +75 -0
- package/dist/runtime/secrets.js.map +1 -0
- package/dist/worker-runtime/index.d.ts +79 -0
- package/dist/worker-runtime/index.d.ts.map +1 -0
- package/dist/worker-runtime/index.js +203 -0
- package/dist/worker-runtime/index.js.map +1 -0
- package/package.json +81 -0
- package/templates/default/.nvmrc +1 -0
- package/templates/default/CLAUDE.md +197 -0
- package/templates/default/index.html +13 -0
- package/templates/default/package.json +25 -0
- package/templates/default/public/vite.svg +1 -0
- package/templates/default/skills/fling/API.md +335 -0
- package/templates/default/skills/fling/EXAMPLES.md +204 -0
- package/templates/default/skills/fling/FEEDBACK.md +73 -0
- package/templates/default/skills/fling/SKILL.md +159 -0
- package/templates/default/src/react-app/App.css +34 -0
- package/templates/default/src/react-app/App.tsx +27 -0
- package/templates/default/src/react-app/index.css +15 -0
- package/templates/default/src/react-app/main.tsx +10 -0
- package/templates/default/src/react-app/vite-env.d.ts +1 -0
- package/templates/default/src/worker/index.ts +27 -0
- package/templates/default/tsconfig.app.json +22 -0
- package/templates/default/tsconfig.json +7 -0
- package/templates/default/tsconfig.worker.json +11 -0
- package/templates/default/vite.config.ts +21 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/cli/commands/register.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fling secret - Secrets management commands
|
|
3
|
+
*
|
|
4
|
+
* Behavior:
|
|
5
|
+
* - Secrets are always stored locally in .fling/secrets
|
|
6
|
+
* - Use `fling push` to deploy secrets to production
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
export declare function loadLocalSecrets(): Map<string, string>;
|
|
10
|
+
export declare const secretCommand: Command;
|
|
11
|
+
//# sourceMappingURL=secret.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/secret.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,gBAAgB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAoBtD;AAoBD,eAAO,MAAM,aAAa,SAcxB,CAAC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fling secret - Secrets management commands
|
|
3
|
+
*
|
|
4
|
+
* Behavior:
|
|
5
|
+
* - Secrets are always stored locally in .fling/secrets
|
|
6
|
+
* - Use `fling push` to deploy secrets to production
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { join, dirname } from "node:path";
|
|
11
|
+
const SECRETS_PATH = join(process.cwd(), ".fling", "secrets");
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Local secrets management
|
|
14
|
+
// ============================================================================
|
|
15
|
+
export function loadLocalSecrets() {
|
|
16
|
+
const secrets = new Map();
|
|
17
|
+
if (existsSync(SECRETS_PATH)) {
|
|
18
|
+
const content = readFileSync(SECRETS_PATH, "utf-8");
|
|
19
|
+
for (const line of content.split("\n")) {
|
|
20
|
+
const trimmed = line.trim();
|
|
21
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const eqIndex = trimmed.indexOf("=");
|
|
25
|
+
if (eqIndex > 0) {
|
|
26
|
+
const key = trimmed.slice(0, eqIndex);
|
|
27
|
+
const value = trimmed.slice(eqIndex + 1);
|
|
28
|
+
secrets.set(key, value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return secrets;
|
|
33
|
+
}
|
|
34
|
+
function saveLocalSecrets(secrets) {
|
|
35
|
+
const dir = dirname(SECRETS_PATH);
|
|
36
|
+
if (!existsSync(dir)) {
|
|
37
|
+
mkdirSync(dir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
const lines = ["# Fling secrets", "# Format: KEY=value", ""];
|
|
40
|
+
for (const [key, value] of secrets) {
|
|
41
|
+
lines.push(`${key}=${value}`);
|
|
42
|
+
}
|
|
43
|
+
writeFileSync(SECRETS_PATH, lines.join("\n") + "\n", { mode: 0o600 });
|
|
44
|
+
}
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// Commands
|
|
47
|
+
// ============================================================================
|
|
48
|
+
export const secretCommand = new Command("secret")
|
|
49
|
+
.description("Manage secrets for your project")
|
|
50
|
+
.addHelpText("after", `
|
|
51
|
+
Environment:
|
|
52
|
+
Secrets are stored locally in .fling/secrets (gitignored).
|
|
53
|
+
Use 'fling push' to deploy secrets to production.
|
|
54
|
+
|
|
55
|
+
Secret naming:
|
|
56
|
+
Names must be UPPER_SNAKE_CASE (e.g., GITHUB_TOKEN, API_KEY, DB_PASSWORD).
|
|
57
|
+
|
|
58
|
+
Examples:
|
|
59
|
+
fling secret list List secret names
|
|
60
|
+
fling secret set API_KEY=xxx Set a secret
|
|
61
|
+
fling secret remove API_KEY Remove a secret
|
|
62
|
+
`);
|
|
63
|
+
secretCommand
|
|
64
|
+
.command("set <keyvalue>")
|
|
65
|
+
.description("Set a secret (must be UPPER_SNAKE_CASE=value format)")
|
|
66
|
+
.addHelpText("after", `
|
|
67
|
+
Examples:
|
|
68
|
+
fling secret set GITHUB_TOKEN=ghp_xxx
|
|
69
|
+
fling secret set API_KEY=secret123
|
|
70
|
+
`)
|
|
71
|
+
.action((keyvalue) => {
|
|
72
|
+
const eqIndex = keyvalue.indexOf("=");
|
|
73
|
+
if (eqIndex <= 0) {
|
|
74
|
+
console.error("Error: Invalid format. Use: fling secret set KEY=value");
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
const key = keyvalue.slice(0, eqIndex);
|
|
78
|
+
const value = keyvalue.slice(eqIndex + 1);
|
|
79
|
+
if (!key.match(/^[A-Z_][A-Z0-9_]*$/)) {
|
|
80
|
+
console.error("Error: Secret name must be uppercase with underscores (e.g., GITHUB_TOKEN)");
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
const secrets = loadLocalSecrets();
|
|
84
|
+
const exists = secrets.has(key);
|
|
85
|
+
secrets.set(key, value);
|
|
86
|
+
saveLocalSecrets(secrets);
|
|
87
|
+
console.log(exists ? `Updated secret: ${key}` : `Set secret: ${key}`);
|
|
88
|
+
});
|
|
89
|
+
secretCommand
|
|
90
|
+
.command("list")
|
|
91
|
+
.description("List all secret names (values are never shown)")
|
|
92
|
+
.addHelpText("after", `
|
|
93
|
+
Examples:
|
|
94
|
+
fling secret list List secrets
|
|
95
|
+
`)
|
|
96
|
+
.action(() => {
|
|
97
|
+
const secrets = loadLocalSecrets();
|
|
98
|
+
if (secrets.size === 0) {
|
|
99
|
+
console.log("No secrets configured.");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
console.log("Configured secrets:");
|
|
103
|
+
for (const key of secrets.keys()) {
|
|
104
|
+
console.log(` ${key}`);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
secretCommand
|
|
108
|
+
.command("remove <key>")
|
|
109
|
+
.description("Delete a secret by name")
|
|
110
|
+
.addHelpText("after", `
|
|
111
|
+
Examples:
|
|
112
|
+
fling secret remove API_KEY Remove a secret
|
|
113
|
+
`)
|
|
114
|
+
.action((key) => {
|
|
115
|
+
const secrets = loadLocalSecrets();
|
|
116
|
+
if (!secrets.has(key)) {
|
|
117
|
+
console.error(`Error: Secret "${key}" not found.`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
secrets.delete(key);
|
|
121
|
+
saveLocalSecrets(secrets);
|
|
122
|
+
console.log(`Removed secret: ${key}`);
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=secret.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret.js","sourceRoot":"","sources":["../../../src/cli/commands/secret.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/whoami.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBpC,eAAO,MAAM,aAAa,SAoDtB,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fling whoami - Show current user and project info
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import { isLoggedIn, platformFetch } from "../utils/config.js";
|
|
6
|
+
export const whoamiCommand = new Command("whoami")
|
|
7
|
+
.description("Display current logged-in user and project information")
|
|
8
|
+
.addHelpText("after", `
|
|
9
|
+
Displays:
|
|
10
|
+
- User name and email
|
|
11
|
+
- Project slug and public URL
|
|
12
|
+
- Current deployment version
|
|
13
|
+
- Last deployment timestamp
|
|
14
|
+
|
|
15
|
+
Requires login (run 'fling login' first).
|
|
16
|
+
`)
|
|
17
|
+
.action(async () => {
|
|
18
|
+
if (!isLoggedIn()) {
|
|
19
|
+
console.log("Not logged in. Run 'fling login' first.");
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const response = await platformFetch("/me");
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
const data = await response.json();
|
|
26
|
+
console.error(`Error: ${data.error ?? "Unknown error"}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
console.log(`User: ${data.user.name} (${data.user.email})`);
|
|
31
|
+
// Display first project (currently users have one project with id 'default')
|
|
32
|
+
const project = data.projects[0];
|
|
33
|
+
if (!project) {
|
|
34
|
+
console.log("No projects found.");
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.log(`Project: ${project.slug}`);
|
|
38
|
+
console.log(`URL: ${project.url}`);
|
|
39
|
+
console.log(`Version: ${project.current_version}`);
|
|
40
|
+
if (project.last_deployed_at) {
|
|
41
|
+
const deployedAt = new Date(project.last_deployed_at);
|
|
42
|
+
console.log(`Last deployed: ${deployedAt.toLocaleString()}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.log("Last deployed: never");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error(`Error: ${error instanceof Error ? error.message : "Network error"}`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=whoami.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../../src/cli/commands/whoami.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAoB/D,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,wDAAwD,CAAC;KACrE,WAAW,CAAC,OAAO,EAAE;;;;;;;;CAQvB,CAAC;KACC,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;QAE5C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAwB,CAAC;YACzD,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC;YACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAgB,CAAC;QAEjD,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QAE5D,6EAA6E;QAC7E,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,QAAQ,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;YAEnD,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;gBAC7B,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;gBACtD,OAAO,CAAC,GAAG,CAAC,kBAAkB,UAAU,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YAC/D,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CACX,UAAU,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CACrE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset collection and hashing for static file uploads.
|
|
3
|
+
* Scans dist/client/ directory and prepares assets for Cloudflare upload.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Get MIME type for a file path based on extension.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getMimeType(filePath: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Represents a single static asset file.
|
|
11
|
+
*/
|
|
12
|
+
export interface AssetFile {
|
|
13
|
+
/** URL path (e.g., "/index.html", "/images/logo.png") */
|
|
14
|
+
path: string;
|
|
15
|
+
/** Full path on disk */
|
|
16
|
+
localPath: string;
|
|
17
|
+
/** 32-character hex hash (project-scoped) */
|
|
18
|
+
hash: string;
|
|
19
|
+
/** File size in bytes */
|
|
20
|
+
size: number;
|
|
21
|
+
/** MIME type for Content-Type header */
|
|
22
|
+
contentType: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Manifest format for Cloudflare's upload session API.
|
|
26
|
+
*/
|
|
27
|
+
export interface AssetManifest {
|
|
28
|
+
[path: string]: {
|
|
29
|
+
hash: string;
|
|
30
|
+
size: number;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Maximum size per file: 25MB */
|
|
34
|
+
export declare const MAX_FILE_SIZE: number;
|
|
35
|
+
/** Maximum total size for all assets: 100MB */
|
|
36
|
+
export declare const MAX_TOTAL_SIZE: number;
|
|
37
|
+
/**
|
|
38
|
+
* Scan dist/client/ directory recursively and collect asset files.
|
|
39
|
+
* Hidden files and directories (starting with .) are ignored.
|
|
40
|
+
*
|
|
41
|
+
* @param projectDir - The project root directory
|
|
42
|
+
* @param userId - User ID for hash scoping
|
|
43
|
+
* @param projectId - Project ID for hash scoping
|
|
44
|
+
* @returns Array of asset files found
|
|
45
|
+
*/
|
|
46
|
+
export declare function collectAssets(projectDir: string, userId: string, projectId: string): Promise<AssetFile[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Generate a globally unique hash for an asset file.
|
|
49
|
+
* Hash includes userId AND projectId to ensure asset isolation between users
|
|
50
|
+
* and projects (projectId alone is not globally unique).
|
|
51
|
+
*
|
|
52
|
+
* @param userId - User ID (UUID)
|
|
53
|
+
* @param projectId - Project ID
|
|
54
|
+
* @param content - File content as Uint8Array
|
|
55
|
+
* @returns 32-character hex hash
|
|
56
|
+
*/
|
|
57
|
+
export declare function hashAssetFile(userId: string, projectId: string, content: Uint8Array): Promise<string>;
|
|
58
|
+
/**
|
|
59
|
+
* Build manifest for Cloudflare's asset upload session API.
|
|
60
|
+
*
|
|
61
|
+
* @param assets - Array of asset files
|
|
62
|
+
* @returns Manifest object for Cloudflare API
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildManifest(assets: AssetFile[]): AssetManifest;
|
|
65
|
+
/**
|
|
66
|
+
* Validate asset sizes against limits.
|
|
67
|
+
* Throws descriptive error if limits are exceeded.
|
|
68
|
+
*
|
|
69
|
+
* @param assets - Array of asset files to validate
|
|
70
|
+
* @throws Error if any file exceeds MAX_FILE_SIZE or total exceeds MAX_TOTAL_SIZE
|
|
71
|
+
*/
|
|
72
|
+
export declare function validateAssetSizes(assets: AssetFile[]): void;
|
|
73
|
+
//# sourceMappingURL=assets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../../src/cli/deploy/assets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+CH;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AAED,kCAAkC;AAClC,eAAO,MAAM,aAAa,QAAmB,CAAC;AAE9C,+CAA+C;AAC/C,eAAO,MAAM,cAAc,QAAoB,CAAC;AAEhD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,SAAS,EAAE,CAAC,CAUtB;AAqDD;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,aAAa,CAMhE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAiB5D"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset collection and hashing for static file uploads.
|
|
3
|
+
* Scans dist/client/ directory and prepares assets for Cloudflare upload.
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
6
|
+
import { join, relative, posix, extname } from "node:path";
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
/**
|
|
9
|
+
* MIME type mapping for common file extensions.
|
|
10
|
+
* Uses text/javascript per HTML Living Standard recommendation.
|
|
11
|
+
* Includes charset=utf-8 for text-based types.
|
|
12
|
+
*/
|
|
13
|
+
const MIME_TYPES = {
|
|
14
|
+
// Text/code with charset
|
|
15
|
+
".html": "text/html; charset=utf-8",
|
|
16
|
+
".css": "text/css; charset=utf-8",
|
|
17
|
+
".js": "text/javascript; charset=utf-8",
|
|
18
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
19
|
+
".json": "application/json; charset=utf-8",
|
|
20
|
+
".txt": "text/plain; charset=utf-8",
|
|
21
|
+
".xml": "application/xml; charset=utf-8",
|
|
22
|
+
".svg": "image/svg+xml; charset=utf-8",
|
|
23
|
+
".map": "application/json; charset=utf-8",
|
|
24
|
+
// Images
|
|
25
|
+
".png": "image/png",
|
|
26
|
+
".jpg": "image/jpeg",
|
|
27
|
+
".jpeg": "image/jpeg",
|
|
28
|
+
".gif": "image/gif",
|
|
29
|
+
".webp": "image/webp",
|
|
30
|
+
".avif": "image/avif",
|
|
31
|
+
".ico": "image/x-icon",
|
|
32
|
+
// Fonts
|
|
33
|
+
".woff": "font/woff",
|
|
34
|
+
".woff2": "font/woff2",
|
|
35
|
+
".ttf": "font/ttf",
|
|
36
|
+
".otf": "font/otf",
|
|
37
|
+
".eot": "application/vnd.ms-fontobject",
|
|
38
|
+
// Media
|
|
39
|
+
".mp4": "video/mp4",
|
|
40
|
+
".webm": "video/webm",
|
|
41
|
+
".mp3": "audio/mpeg",
|
|
42
|
+
".ogg": "audio/ogg",
|
|
43
|
+
// Other
|
|
44
|
+
".wasm": "application/wasm",
|
|
45
|
+
".webmanifest": "application/manifest+json",
|
|
46
|
+
".pdf": "application/pdf",
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Get MIME type for a file path based on extension.
|
|
50
|
+
*/
|
|
51
|
+
export function getMimeType(filePath) {
|
|
52
|
+
const ext = extname(filePath).toLowerCase();
|
|
53
|
+
return MIME_TYPES[ext] ?? "application/octet-stream";
|
|
54
|
+
}
|
|
55
|
+
/** Maximum size per file: 25MB */
|
|
56
|
+
export const MAX_FILE_SIZE = 25 * 1024 * 1024;
|
|
57
|
+
/** Maximum total size for all assets: 100MB */
|
|
58
|
+
export const MAX_TOTAL_SIZE = 100 * 1024 * 1024;
|
|
59
|
+
/**
|
|
60
|
+
* Scan dist/client/ directory recursively and collect asset files.
|
|
61
|
+
* Hidden files and directories (starting with .) are ignored.
|
|
62
|
+
*
|
|
63
|
+
* @param projectDir - The project root directory
|
|
64
|
+
* @param userId - User ID for hash scoping
|
|
65
|
+
* @param projectId - Project ID for hash scoping
|
|
66
|
+
* @returns Array of asset files found
|
|
67
|
+
*/
|
|
68
|
+
export async function collectAssets(projectDir, userId, projectId) {
|
|
69
|
+
const clientDir = join(projectDir, "dist", "client");
|
|
70
|
+
if (!existsSync(clientDir)) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const assets = [];
|
|
74
|
+
await scanDirectory(clientDir, clientDir, userId, projectId, assets);
|
|
75
|
+
return assets;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Recursively scan a directory for files.
|
|
79
|
+
*/
|
|
80
|
+
async function scanDirectory(baseDir, currentDir, userId, projectId, assets) {
|
|
81
|
+
const entries = readdirSync(currentDir, { withFileTypes: true });
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
// Skip hidden files and directories
|
|
84
|
+
if (entry.name.startsWith(".")) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const fullPath = join(currentDir, entry.name);
|
|
88
|
+
if (entry.isDirectory()) {
|
|
89
|
+
await scanDirectory(baseDir, fullPath, userId, projectId, assets);
|
|
90
|
+
}
|
|
91
|
+
else if (entry.isFile()) {
|
|
92
|
+
// Check file size before reading to avoid OOM on oversized files
|
|
93
|
+
const stats = statSync(fullPath);
|
|
94
|
+
if (stats.size > MAX_FILE_SIZE) {
|
|
95
|
+
const relativePath = relative(baseDir, fullPath);
|
|
96
|
+
const urlPath = "/" + relativePath.split(/[/\\]/).join(posix.sep);
|
|
97
|
+
throw new Error(`File ${urlPath} exceeds 25MB limit (${(stats.size / 1024 / 1024).toFixed(1)}MB)`);
|
|
98
|
+
}
|
|
99
|
+
const content = readFileSync(fullPath);
|
|
100
|
+
const hash = await hashAssetFile(userId, projectId, content);
|
|
101
|
+
const relativePath = relative(baseDir, fullPath);
|
|
102
|
+
// Use POSIX path separators for URL paths
|
|
103
|
+
const urlPath = "/" + relativePath.split(/[/\\]/).join(posix.sep);
|
|
104
|
+
const contentType = getMimeType(urlPath);
|
|
105
|
+
assets.push({
|
|
106
|
+
path: urlPath,
|
|
107
|
+
localPath: fullPath,
|
|
108
|
+
hash,
|
|
109
|
+
size: content.length,
|
|
110
|
+
contentType,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Generate a globally unique hash for an asset file.
|
|
117
|
+
* Hash includes userId AND projectId to ensure asset isolation between users
|
|
118
|
+
* and projects (projectId alone is not globally unique).
|
|
119
|
+
*
|
|
120
|
+
* @param userId - User ID (UUID)
|
|
121
|
+
* @param projectId - Project ID
|
|
122
|
+
* @param content - File content as Uint8Array
|
|
123
|
+
* @returns 32-character hex hash
|
|
124
|
+
*/
|
|
125
|
+
export async function hashAssetFile(userId, projectId, content) {
|
|
126
|
+
const hash = createHash("sha256");
|
|
127
|
+
// Include userId and projectId in the hash for isolation
|
|
128
|
+
hash.update(userId);
|
|
129
|
+
hash.update(projectId);
|
|
130
|
+
hash.update(content);
|
|
131
|
+
// Truncate to 32 hex characters (16 bytes) as per Cloudflare spec
|
|
132
|
+
return hash.digest("hex").slice(0, 32);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Build manifest for Cloudflare's asset upload session API.
|
|
136
|
+
*
|
|
137
|
+
* @param assets - Array of asset files
|
|
138
|
+
* @returns Manifest object for Cloudflare API
|
|
139
|
+
*/
|
|
140
|
+
export function buildManifest(assets) {
|
|
141
|
+
const manifest = {};
|
|
142
|
+
for (const asset of assets) {
|
|
143
|
+
manifest[asset.path] = { hash: asset.hash, size: asset.size };
|
|
144
|
+
}
|
|
145
|
+
return manifest;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Validate asset sizes against limits.
|
|
149
|
+
* Throws descriptive error if limits are exceeded.
|
|
150
|
+
*
|
|
151
|
+
* @param assets - Array of asset files to validate
|
|
152
|
+
* @throws Error if any file exceeds MAX_FILE_SIZE or total exceeds MAX_TOTAL_SIZE
|
|
153
|
+
*/
|
|
154
|
+
export function validateAssetSizes(assets) {
|
|
155
|
+
// Check individual file sizes first
|
|
156
|
+
for (const asset of assets) {
|
|
157
|
+
if (asset.size > MAX_FILE_SIZE) {
|
|
158
|
+
throw new Error(`File ${asset.path} exceeds 25MB limit (${(asset.size / 1024 / 1024).toFixed(1)}MB)`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Check total size
|
|
162
|
+
const totalSize = assets.reduce((sum, asset) => sum + asset.size, 0);
|
|
163
|
+
if (totalSize > MAX_TOTAL_SIZE) {
|
|
164
|
+
throw new Error(`Total assets exceed 100MB limit (${Math.round(totalSize / 1024 / 1024)}MB)`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assets.js","sourceRoot":"","sources":["../../../src/cli/deploy/assets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming base64 encoder for memory-efficient file uploads.
|
|
3
|
+
* Handles the 3-byte-to-4-char base64 encoding in a streaming fashion.
|
|
4
|
+
*/
|
|
5
|
+
import { Transform } from "node:stream";
|
|
6
|
+
/**
|
|
7
|
+
* Create a Transform stream that base64-encodes input bytes.
|
|
8
|
+
* Handles buffering for the 3-byte input requirement.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createBase64EncodeStream(): Transform;
|
|
11
|
+
/**
|
|
12
|
+
* Calculate base64-encoded size for a given raw size.
|
|
13
|
+
* Base64 encodes 3 bytes into 4 characters.
|
|
14
|
+
*/
|
|
15
|
+
export declare function base64EncodedSize(rawSize: number): number;
|
|
16
|
+
//# sourceMappingURL=base64-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64-stream.d.ts","sourceRoot":"","sources":["../../../src/cli/deploy/base64-stream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAA0B,MAAM,aAAa,CAAC;AAEhE;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,SAAS,CA4BpD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGzD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming base64 encoder for memory-efficient file uploads.
|
|
3
|
+
* Handles the 3-byte-to-4-char base64 encoding in a streaming fashion.
|
|
4
|
+
*/
|
|
5
|
+
import { Transform } from "node:stream";
|
|
6
|
+
/**
|
|
7
|
+
* Create a Transform stream that base64-encodes input bytes.
|
|
8
|
+
* Handles buffering for the 3-byte input requirement.
|
|
9
|
+
*/
|
|
10
|
+
export function createBase64EncodeStream() {
|
|
11
|
+
let buffer = Buffer.alloc(0);
|
|
12
|
+
return new Transform({
|
|
13
|
+
transform(chunk, _encoding, callback) {
|
|
14
|
+
// Combine buffer with new chunk
|
|
15
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
16
|
+
// Process complete 3-byte groups
|
|
17
|
+
const completeGroups = Math.floor(buffer.length / 3);
|
|
18
|
+
const processBytes = completeGroups * 3;
|
|
19
|
+
if (completeGroups > 0) {
|
|
20
|
+
const toProcess = buffer.subarray(0, processBytes);
|
|
21
|
+
this.push(toProcess.toString("base64"));
|
|
22
|
+
buffer = buffer.subarray(processBytes);
|
|
23
|
+
}
|
|
24
|
+
callback();
|
|
25
|
+
},
|
|
26
|
+
flush(callback) {
|
|
27
|
+
// Handle remaining 1 or 2 bytes with padding
|
|
28
|
+
if (buffer.length > 0) {
|
|
29
|
+
this.push(buffer.toString("base64"));
|
|
30
|
+
}
|
|
31
|
+
callback();
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Calculate base64-encoded size for a given raw size.
|
|
37
|
+
* Base64 encodes 3 bytes into 4 characters.
|
|
38
|
+
*/
|
|
39
|
+
export function base64EncodedSize(rawSize) {
|
|
40
|
+
if (rawSize === 0)
|
|
41
|
+
return 0;
|
|
42
|
+
return Math.ceil(rawSize / 3) * 4;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=base64-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64-stream.js","sourceRoot":"","sources":["../../../src/cli/deploy/base64-stream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAA0B,MAAM,aAAa,CAAC;AAEhE;;;GAGG;AACH,MAAM,UAAU,wBAAwB;IACtC,IAAI,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE7B,OAAO,IAAI,SAAS,CAAC;QACnB,SAAS,CAAC,KAAa,EAAE,SAAyB,EAAE,QAA2B;YAC7E,gCAAgC;YAChC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;YAExC,iCAAiC;YACjC,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACrD,MAAM,YAAY,GAAG,cAAc,GAAG,CAAC,CAAC;YAExC,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;gBACnD,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACxC,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;YACzC,CAAC;YAED,QAAQ,EAAE,CAAC;QACb,CAAC;QACD,KAAK,CAAC,QAA2B;YAC/B,6CAA6C;YAC7C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;YACvC,CAAC;YACD,QAAQ,EAAE,CAAC;QACb,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,IAAI,OAAO,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC5B,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Readable } from "node:stream";
|
|
2
|
+
import type { AssetFile } from "./assets.js";
|
|
3
|
+
/** Fixed boundary for asset uploads - matches what platform expects */
|
|
4
|
+
export declare const BOUNDARY = "----fling-asset";
|
|
5
|
+
/**
|
|
6
|
+
* Create a streaming multipart body for a bucket of assets.
|
|
7
|
+
* All files are base64-encoded as they stream through.
|
|
8
|
+
* Each part includes Content-Type header for proper MIME type serving.
|
|
9
|
+
*
|
|
10
|
+
* @param assets - Array of asset files to include in the multipart body
|
|
11
|
+
* @returns stream - The multipart body stream
|
|
12
|
+
* @returns contentLength - Total content length (for testing validation)
|
|
13
|
+
*/
|
|
14
|
+
export declare function createBucketUploadStream(assets: AssetFile[]): {
|
|
15
|
+
stream: Readable;
|
|
16
|
+
contentLength: number;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=bucket-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bucket-stream.d.ts","sourceRoot":"","sources":["../../../src/cli/deploy/bucket-stream.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,uEAAuE;AACvE,eAAO,MAAM,QAAQ,oBAAoB,CAAC;AAE1C;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,EAAE,GAClB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAkD7C"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a streaming multipart body for uploading a bucket of assets.
|
|
3
|
+
* Streams multiple files with base64 encoding in a single request.
|
|
4
|
+
*/
|
|
5
|
+
import { createReadStream } from "node:fs";
|
|
6
|
+
import { PassThrough } from "node:stream";
|
|
7
|
+
import { pipeline } from "node:stream/promises";
|
|
8
|
+
import { createBase64EncodeStream, base64EncodedSize } from "./base64-stream.js";
|
|
9
|
+
/** Fixed boundary for asset uploads - matches what platform expects */
|
|
10
|
+
export const BOUNDARY = "----fling-asset";
|
|
11
|
+
/**
|
|
12
|
+
* Create a streaming multipart body for a bucket of assets.
|
|
13
|
+
* All files are base64-encoded as they stream through.
|
|
14
|
+
* Each part includes Content-Type header for proper MIME type serving.
|
|
15
|
+
*
|
|
16
|
+
* @param assets - Array of asset files to include in the multipart body
|
|
17
|
+
* @returns stream - The multipart body stream
|
|
18
|
+
* @returns contentLength - Total content length (for testing validation)
|
|
19
|
+
*/
|
|
20
|
+
export function createBucketUploadStream(assets) {
|
|
21
|
+
// Calculate total content length for validation
|
|
22
|
+
// Header includes Content-Disposition AND Content-Type
|
|
23
|
+
// Use Buffer.byteLength for safety with non-ASCII chars in Content-Type (e.g., charset)
|
|
24
|
+
let contentLength = 0;
|
|
25
|
+
for (const asset of assets) {
|
|
26
|
+
const header = `--${BOUNDARY}\r\n` +
|
|
27
|
+
`Content-Disposition: form-data; name="${asset.hash}"\r\n` +
|
|
28
|
+
`Content-Type: ${asset.contentType}\r\n` +
|
|
29
|
+
`\r\n`;
|
|
30
|
+
const base64Size = base64EncodedSize(asset.size);
|
|
31
|
+
contentLength += Buffer.byteLength(header, "utf8") + base64Size + 2; // +2 for \r\n after content
|
|
32
|
+
}
|
|
33
|
+
contentLength += Buffer.byteLength(`--${BOUNDARY}--\r\n`, "utf8");
|
|
34
|
+
// Create streaming pipeline that yields parts one by one
|
|
35
|
+
const output = new PassThrough();
|
|
36
|
+
void (async () => {
|
|
37
|
+
try {
|
|
38
|
+
for (const asset of assets) {
|
|
39
|
+
// Write part header with Content-Type for proper MIME serving
|
|
40
|
+
const header = `--${BOUNDARY}\r\n` +
|
|
41
|
+
`Content-Disposition: form-data; name="${asset.hash}"\r\n` +
|
|
42
|
+
`Content-Type: ${asset.contentType}\r\n` +
|
|
43
|
+
`\r\n`;
|
|
44
|
+
output.write(header);
|
|
45
|
+
// Stream file through base64 encoder
|
|
46
|
+
const fileStream = createReadStream(asset.localPath);
|
|
47
|
+
const base64Stream = fileStream.pipe(createBase64EncodeStream());
|
|
48
|
+
// Pipe base64 stream to output without ending output
|
|
49
|
+
await pipeline(base64Stream, output, { end: false });
|
|
50
|
+
// Write part terminator
|
|
51
|
+
output.write("\r\n");
|
|
52
|
+
}
|
|
53
|
+
// Write final boundary
|
|
54
|
+
output.write(`--${BOUNDARY}--\r\n`);
|
|
55
|
+
output.end();
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
output.destroy(err instanceof Error ? err : new Error(String(err)));
|
|
59
|
+
}
|
|
60
|
+
})();
|
|
61
|
+
return { stream: output, contentLength };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=bucket-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bucket-stream.js","sourceRoot":"","sources":["../../../src/cli/deploy/bucket-stream.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAiB,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAGjF,uEAAuE;AACvE,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAAmB;IAEnB,gDAAgD;IAChD,uDAAuD;IACvD,wFAAwF;IACxF,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,MAAM,GACV,KAAK,QAAQ,MAAM;YACnB,yCAAyC,KAAK,CAAC,IAAI,OAAO;YAC1D,iBAAiB,KAAK,CAAC,WAAW,MAAM;YACxC,MAAM,CAAC;QACT,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,aAAa,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,4BAA4B;IACnG,CAAC;IACD,aAAa,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,QAAQ,QAAQ,EAAE,MAAM,CAAC,CAAC;IAElE,yDAAyD;IACzD,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;IAEjC,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,IAAI,CAAC;YACH,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,8DAA8D;gBAC9D,MAAM,MAAM,GACV,KAAK,QAAQ,MAAM;oBACnB,yCAAyC,KAAK,CAAC,IAAI,OAAO;oBAC1D,iBAAiB,KAAK,CAAC,WAAW,MAAM;oBACxC,MAAM,CAAC;gBACT,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAErB,qCAAqC;gBACrC,MAAM,UAAU,GAAG,gBAAgB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACrD,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC;gBAEjE,qDAAqD;gBACrD,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;gBAErD,wBAAwB;gBACxB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;YAED,uBAAuB;YACvB,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,QAAQ,CAAC,CAAC;YACpC,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,OAAO,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AAC3C,CAAC"}
|