kap-r2 1.1.0 → 1.3.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.
- package/dist/index.d.ts +15 -0
- package/dist/index.js +21 -30
- package/package.json +5 -2
- package/readme.md +17 -97
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
interface KapConfig {
|
|
2
2
|
get(key: string): string;
|
|
3
3
|
}
|
|
4
|
+
interface RequestOptions {
|
|
5
|
+
method?: string;
|
|
6
|
+
headers?: Record<string, string | number | undefined>;
|
|
7
|
+
body?: Buffer;
|
|
8
|
+
}
|
|
4
9
|
interface KapContext {
|
|
5
10
|
filePath(): Promise<string>;
|
|
6
11
|
config: KapConfig;
|
|
12
|
+
request(url: string, options?: RequestOptions): Promise<{
|
|
13
|
+
body: string;
|
|
14
|
+
}>;
|
|
7
15
|
setProgress(text: string, percentage?: number): void;
|
|
8
16
|
copyToClipboard(text: string): void;
|
|
9
17
|
notify(text: string, action?: () => void): void;
|
|
@@ -51,6 +59,13 @@ export declare const shareServices: {
|
|
|
51
59
|
default: string;
|
|
52
60
|
required: boolean;
|
|
53
61
|
};
|
|
62
|
+
addTimestamp: {
|
|
63
|
+
title: string;
|
|
64
|
+
description: string;
|
|
65
|
+
type: string;
|
|
66
|
+
default: boolean;
|
|
67
|
+
required: boolean;
|
|
68
|
+
};
|
|
54
69
|
};
|
|
55
70
|
}[];
|
|
56
71
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.shareServices = void 0;
|
|
7
7
|
const promises_1 = require("fs/promises");
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const https_1 = __importDefault(require("https"));
|
|
10
9
|
const aws4_1 = __importDefault(require("aws4"));
|
|
11
10
|
const contentTypes = new Map([
|
|
12
11
|
[".gif", "image/gif"],
|
|
@@ -37,29 +36,31 @@ const action = async (context) => {
|
|
|
37
36
|
context.cancel();
|
|
38
37
|
return;
|
|
39
38
|
}
|
|
40
|
-
if (
|
|
41
|
-
context.notify("Public URL must
|
|
39
|
+
if (!/^https:\/\/.+/.test(publicUrl)) {
|
|
40
|
+
context.notify("Public URL must be a valid https:// URL");
|
|
42
41
|
context.cancel();
|
|
43
42
|
return;
|
|
44
43
|
}
|
|
45
44
|
const filePath = await context.filePath();
|
|
46
|
-
const fileStats = await (0, promises_1.stat)(filePath);
|
|
47
45
|
const fileBuffer = await (0, promises_1.readFile)(filePath);
|
|
48
46
|
context.setProgress("Uploading to R2…", 0);
|
|
49
|
-
const
|
|
47
|
+
const addTimestamp = context.config.get("addTimestamp") === "true";
|
|
48
|
+
const originalFilename = path_1.default.basename(filePath);
|
|
49
|
+
const filename = addTimestamp ? `${Date.now()}-${originalFilename}` : originalFilename;
|
|
50
50
|
const key = directory ? path_1.default.posix.join(directory, filename) : filename;
|
|
51
51
|
const extension = path_1.default.extname(filename);
|
|
52
52
|
const contentType = contentTypes.get(extension) || "application/octet-stream";
|
|
53
53
|
const host = `${accountId}.r2.cloudflarestorage.com`;
|
|
54
54
|
const encodedKey = key.split("/").map(encodeURIComponent).join("/");
|
|
55
55
|
const fullPath = `/${bucket}/${encodedKey}`;
|
|
56
|
-
const
|
|
56
|
+
const url = `https://${host}${fullPath}`;
|
|
57
|
+
const signed = aws4_1.default.sign({
|
|
57
58
|
host,
|
|
58
59
|
path: fullPath,
|
|
59
60
|
method: "PUT",
|
|
60
61
|
headers: {
|
|
61
62
|
"Content-Type": contentType,
|
|
62
|
-
"Content-Length":
|
|
63
|
+
"Content-Length": fileBuffer.length,
|
|
63
64
|
},
|
|
64
65
|
body: fileBuffer,
|
|
65
66
|
service: "s3",
|
|
@@ -69,28 +70,11 @@ const action = async (context) => {
|
|
|
69
70
|
secretAccessKey,
|
|
70
71
|
});
|
|
71
72
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
headers: request.headers,
|
|
78
|
-
}, (res) => {
|
|
79
|
-
const chunks = [];
|
|
80
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
81
|
-
res.on("end", () => {
|
|
82
|
-
const body = Buffer.concat(chunks).toString();
|
|
83
|
-
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
84
|
-
resolve();
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
reject(new Error(`HTTP ${res.statusCode}: ${body}`));
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
req.on("error", reject);
|
|
92
|
-
context.setProgress("Uploading to R2…", 0.5);
|
|
93
|
-
req.end(fileBuffer);
|
|
73
|
+
context.setProgress("Uploading to R2…", 0.5);
|
|
74
|
+
await context.request(url, {
|
|
75
|
+
method: "PUT",
|
|
76
|
+
headers: signed.headers,
|
|
77
|
+
body: fileBuffer,
|
|
94
78
|
});
|
|
95
79
|
const baseUrl = publicUrl.replace(/\/$/, "");
|
|
96
80
|
const uploadUrl = `${baseUrl}/${encodedKey}`;
|
|
@@ -118,7 +102,7 @@ const r2 = {
|
|
|
118
102
|
title: "Share to R2",
|
|
119
103
|
formats: ["gif", "mp4", "webm", "apng"],
|
|
120
104
|
action,
|
|
121
|
-
configDescription: "Configure your Cloudflare R2 credentials. Get your API tokens from
|
|
105
|
+
configDescription: "Configure your Cloudflare R2 credentials. Get your API tokens from https://dash.cloudflare.com/?to=/:account/r2/api-tokens",
|
|
122
106
|
config: {
|
|
123
107
|
accountId: {
|
|
124
108
|
title: "Account ID",
|
|
@@ -156,6 +140,13 @@ const r2 = {
|
|
|
156
140
|
default: "",
|
|
157
141
|
required: true,
|
|
158
142
|
},
|
|
143
|
+
addTimestamp: {
|
|
144
|
+
title: "Add Timestamp to Filename",
|
|
145
|
+
description: "Prefix filenames with timestamp to avoid overwrites",
|
|
146
|
+
type: "boolean",
|
|
147
|
+
default: false,
|
|
148
|
+
required: false,
|
|
149
|
+
},
|
|
159
150
|
},
|
|
160
151
|
};
|
|
161
152
|
exports.shareServices = [r2];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kap-r2",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Share on Cloudflare R2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tristanremy/kap-r2",
|
|
@@ -29,12 +29,15 @@
|
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/aws4": "^1.11.6",
|
|
31
31
|
"@types/node": "^20.0.0",
|
|
32
|
+
"ava": "^5.3.1",
|
|
33
|
+
"kap-plugin-test": "^0.5.0",
|
|
32
34
|
"typescript": "^5.0.0"
|
|
33
35
|
},
|
|
34
36
|
"engines": {
|
|
35
37
|
"node": ">=14"
|
|
36
38
|
},
|
|
37
39
|
"scripts": {
|
|
38
|
-
"build": "tsc"
|
|
40
|
+
"build": "tsc",
|
|
41
|
+
"test": "pnpm build && ava"
|
|
39
42
|
}
|
|
40
43
|
}
|
package/readme.md
CHANGED
|
@@ -1,110 +1,30 @@
|
|
|
1
1
|
# kap-r2
|
|
2
2
|
|
|
3
|
-
> [Kap](https://github.com/wulkano/
|
|
4
|
-
|
|
5
|
-
Instantly share your Kap screen recordings via Cloudflare R2 storage. After recording, your file is uploaded and the public URL is automatically copied to your clipboard.
|
|
3
|
+
> [Kap](https://github.com/wulkano/kap) plugin - Share on [Cloudflare R2](https://www.cloudflare.com/products/r2/)
|
|
6
4
|
|
|
7
5
|
## Install
|
|
8
6
|
|
|
9
|
-
In the `Kap` menu, go to `Preferences…`, select the `Plugins` pane,
|
|
10
|
-
|
|
11
|
-
## Configuration
|
|
12
|
-
|
|
13
|
-
After installing, click the gear icon next to the plugin to configure it.
|
|
14
|
-
|
|
15
|
-
| Setting | Description |
|
|
16
|
-
|---------|-------------|
|
|
17
|
-
| **Account ID** | Your Cloudflare account ID (32-character hex string) |
|
|
18
|
-
| **Access Key ID** | R2 API token access key |
|
|
19
|
-
| **Secret Access Key** | R2 API token secret |
|
|
20
|
-
| **Bucket Name** | Name of your R2 bucket |
|
|
21
|
-
| **Directory** | Optional subfolder path (e.g., `recordings/`) |
|
|
22
|
-
| **Public URL** | Your bucket's public URL (must start with `https://`) |
|
|
23
|
-
|
|
24
|
-
## Setup Guide
|
|
25
|
-
|
|
26
|
-
### Step 1: Find Your Account ID
|
|
27
|
-
|
|
28
|
-
1. Log in to the [Cloudflare Dashboard](https://dash.cloudflare.com)
|
|
29
|
-
2. Select your account
|
|
30
|
-
3. Go to **R2** in the left sidebar
|
|
31
|
-
4. Your **Account ID** is displayed in the right sidebar under "Account details"
|
|
32
|
-
|
|
33
|
-
### Step 2: Create an R2 Bucket
|
|
34
|
-
|
|
35
|
-
1. In the R2 section, click **Create bucket**
|
|
36
|
-
2. Enter a bucket name (lowercase letters, numbers, and hyphens only)
|
|
37
|
-
3. Click **Create bucket**
|
|
38
|
-
|
|
39
|
-
### Step 3: Enable Public Access
|
|
40
|
-
|
|
41
|
-
You need to make your bucket publicly accessible. Choose one option:
|
|
42
|
-
|
|
43
|
-
#### Option A: R2.dev Subdomain (Easiest)
|
|
44
|
-
|
|
45
|
-
1. Click on your bucket
|
|
46
|
-
2. Go to **Settings** tab
|
|
47
|
-
3. Under "Public access", find **R2.dev subdomain**
|
|
48
|
-
4. Click **Allow Access**
|
|
49
|
-
5. Copy the provided URL (e.g., `https://pub-abc123.r2.dev`)
|
|
50
|
-
|
|
51
|
-
#### Option B: Custom Domain
|
|
52
|
-
|
|
53
|
-
1. Click on your bucket
|
|
54
|
-
2. Go to **Settings** tab
|
|
55
|
-
3. Under "Public access", click **Connect Domain**
|
|
56
|
-
4. Follow the instructions to add your custom domain
|
|
57
|
-
5. Use your domain as the Public URL (e.g., `https://cdn.yourdomain.com`)
|
|
58
|
-
|
|
59
|
-
### Step 4: Create API Credentials
|
|
60
|
-
|
|
61
|
-
1. In the R2 section, click **Manage R2 API Tokens** (top right)
|
|
62
|
-
2. Click **Create API token**
|
|
63
|
-
3. Give it a name (e.g., "Kap Upload")
|
|
64
|
-
4. Under "Permissions", select **Object Read & Write**
|
|
65
|
-
5. Under "Specify bucket(s)", choose your bucket or select "Apply to all buckets"
|
|
66
|
-
6. Click **Create API Token**
|
|
67
|
-
7. **Important**: Copy both the **Access Key ID** and **Secret Access Key** immediately — the secret is only shown once!
|
|
68
|
-
|
|
69
|
-
### Step 5: Configure the Plugin
|
|
70
|
-
|
|
71
|
-
1. Open Kap → Preferences → Plugins
|
|
72
|
-
2. Click the gear icon next to kap-r2
|
|
73
|
-
3. Fill in all the fields:
|
|
74
|
-
- **Account ID**: The 32-character ID from Step 1
|
|
75
|
-
- **Access Key ID**: From Step 4
|
|
76
|
-
- **Secret Access Key**: From Step 4
|
|
77
|
-
- **Bucket Name**: The name you chose in Step 2
|
|
78
|
-
- **Directory**: Leave empty or enter a folder name (optional)
|
|
79
|
-
- **Public URL**: The URL from Step 3 (must start with `https://`)
|
|
7
|
+
In the `Kap` menu, go to `Preferences…`, select the `Plugins` pane, find this plugin, and click `Install`.
|
|
80
8
|
|
|
81
9
|
## Usage
|
|
82
10
|
|
|
83
|
-
1.
|
|
84
|
-
2.
|
|
85
|
-
3.
|
|
86
|
-
4. Wait for the upload to complete
|
|
87
|
-
5. The public URL is automatically copied to your clipboard
|
|
88
|
-
|
|
89
|
-
## Troubleshooting
|
|
90
|
-
|
|
91
|
-
### "Export cancelled" immediately
|
|
92
|
-
- Make sure all required fields are configured in the plugin settings
|
|
93
|
-
- Check that your Account ID is exactly 32 characters (lowercase hex)
|
|
94
|
-
- Verify your Public URL starts with `https://`
|
|
95
|
-
|
|
96
|
-
### Upload fails with authentication error
|
|
97
|
-
- Double-check your Access Key ID and Secret Access Key
|
|
98
|
-
- Make sure your API token has "Object Read & Write" permission
|
|
99
|
-
- Verify the token has access to the specified bucket
|
|
11
|
+
1. Configure your R2 credentials by clicking the gear icon next to the plugin
|
|
12
|
+
2. After recording, select an export format and click `Share to R2`
|
|
13
|
+
3. The public URL is copied to your clipboard
|
|
100
14
|
|
|
101
|
-
|
|
102
|
-
- Check the Cloudflare R2 dashboard to see if the file was uploaded
|
|
103
|
-
- Verify your bucket name is correct (case-sensitive)
|
|
15
|
+
## Configuration
|
|
104
16
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
17
|
+
| Setting | Description |
|
|
18
|
+
|---------|-------------|
|
|
19
|
+
| Account ID | Your Cloudflare account ID (32-character hex) |
|
|
20
|
+
| Access Key ID | R2 API token access key |
|
|
21
|
+
| Secret Access Key | R2 API token secret |
|
|
22
|
+
| Bucket Name | Your R2 bucket name |
|
|
23
|
+
| Directory | Optional subfolder path |
|
|
24
|
+
| Public URL | Your bucket's public URL (e.g., `https://pub-xxx.r2.dev`) |
|
|
25
|
+
| Add Timestamp to Filename | Prefix filenames with timestamp to avoid overwrites |
|
|
26
|
+
|
|
27
|
+
Get your API credentials from the [Cloudflare R2 API Tokens page](https://dash.cloudflare.com/?to=/:account/r2/api-tokens).
|
|
108
28
|
|
|
109
29
|
## License
|
|
110
30
|
|