@rmdes/indiekit-endpoint-activitypub 0.1.9 → 0.1.10

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/index.js CHANGED
@@ -180,7 +180,7 @@ export default class ActivityPubEndpoint {
180
180
  router.get("/admin/activities", activitiesController(mp));
181
181
  router.get("/admin/migrate", migrateGetController(mp, this.options));
182
182
  router.post("/admin/migrate", migratePostController(mp, this.options));
183
- router.post("/admin/migrate/import", express.json({ limit: "5mb" }), migrateImportController(mp, this.options));
183
+ router.post("/admin/migrate/import", migrateImportController(mp, this.options));
184
184
 
185
185
  return router;
186
186
  }
@@ -7,8 +7,6 @@
7
7
  */
8
8
 
9
9
  import {
10
- parseMastodonFollowingCsv,
11
- parseMastodonFollowersList,
12
10
  bulkImportFollowing,
13
11
  bulkImportFollowers,
14
12
  } from "../migration.js";
@@ -56,19 +54,20 @@ export function migratePostController(mountPath, pluginOptions) {
56
54
  }
57
55
 
58
56
  /**
59
- * JSON endpoint for CSV import — receives { csvContent, importTypes }
60
- * via fetch() to bypass Express's app-level urlencoded body size limit.
57
+ * JSON endpoint for import — receives { handles, importTypes }.
58
+ * CSV is parsed client-side to extract handles only, keeping the
59
+ * JSON payload small enough for Express's default body parser limit.
61
60
  */
62
61
  export function migrateImportController(mountPath, pluginOptions) {
63
62
  return async (request, response, next) => {
64
63
  try {
65
64
  const { application } = request.app.locals;
66
- const { csvContent, importTypes } = request.body;
65
+ const { handles, importTypes } = request.body;
67
66
 
68
- if (!csvContent?.trim()) {
67
+ if (!Array.isArray(handles) || handles.length === 0) {
69
68
  return response.status(400).json({
70
69
  type: "error",
71
- text: "No CSV content provided.",
70
+ text: "No handles provided.",
72
71
  });
73
72
  }
74
73
 
@@ -84,15 +83,13 @@ export function migrateImportController(mountPath, pluginOptions) {
84
83
  let followersResult = { imported: 0, failed: 0, errors: [] };
85
84
 
86
85
  if (importFollowing && followingCollection) {
87
- const handles = parseMastodonFollowingCsv(csvContent);
88
- console.log(`[ActivityPub] Migration: parsed ${handles.length} following handles from CSV`);
86
+ console.log(`[ActivityPub] Migration: importing ${handles.length} following handles`);
89
87
  followingResult = await bulkImportFollowing(handles, followingCollection);
90
88
  }
91
89
 
92
90
  if (importFollowers && followersCollection) {
93
- const entries = parseMastodonFollowersList(csvContent);
94
- console.log(`[ActivityPub] Migration: parsed ${entries.length} follower entries from CSV`);
95
- followersResult = await bulkImportFollowers(entries, followersCollection);
91
+ console.log(`[ActivityPub] Migration: importing ${handles.length} follower entries`);
92
+ followersResult = await bulkImportFollowers(handles, followersCollection);
96
93
  }
97
94
 
98
95
  const totalFailed = followingResult.failed + followersResult.failed;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rmdes/indiekit-endpoint-activitypub",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
5
5
  "keywords": [
6
6
  "indiekit",
@@ -76,7 +76,7 @@
76
76
  @change="readFile($event)">
77
77
  <template x-if="fileName">
78
78
  <p class="hint" style="margin-top: 0.5em">
79
- <strong x-text="fileName"></strong> — <span x-text="lineCount + ' lines'"></span>
79
+ <strong x-text="fileName"></strong> — <span x-text="handles.length + ' accounts found'"></span>
80
80
  </p>
81
81
  </template>
82
82
  <template x-if="fileError">
@@ -85,7 +85,7 @@
85
85
  </div>
86
86
 
87
87
  <button class="button" type="button"
88
- :disabled="importing || !csvContent"
88
+ :disabled="importing || handles.length === 0"
89
89
  @click="startImport()">
90
90
  <span x-show="!importing">{{ __("activitypub.migrate.importButton") }}</span>
91
91
  <span x-show="importing" x-text="statusText"></span>
@@ -119,7 +119,7 @@
119
119
  <script>
120
120
  function csvImport(mountPath) {
121
121
  return {
122
- csvContent: '',
122
+ handles: [],
123
123
  fileName: '',
124
124
  lineCount: 0,
125
125
  fileError: '',
@@ -129,9 +129,14 @@
129
129
  resultText: '',
130
130
  resultErrors: [],
131
131
 
132
+ /**
133
+ * Parse CSV client-side — extract handles (first column) only.
134
+ * This keeps the JSON payload small (handles only, no raw CSV),
135
+ * avoiding Express's default 100KB body parser limit.
136
+ */
132
137
  readFile(event) {
133
138
  var self = this;
134
- self.csvContent = '';
139
+ self.handles = [];
135
140
  self.fileName = '';
136
141
  self.lineCount = 0;
137
142
  self.fileError = '';
@@ -151,9 +156,19 @@
151
156
  var reader = new FileReader();
152
157
  reader.onload = function(e) {
153
158
  var text = e.target.result;
154
- self.csvContent = text;
159
+ var lines = text.split('\n').filter(function(l) { return l.trim(); });
155
160
  self.fileName = file.name;
156
- self.lineCount = text.split('\n').filter(function(l) { return l.trim(); }).length;
161
+ self.lineCount = lines.length;
162
+
163
+ // Extract handles: skip header, take first CSV column, keep only valid handles
164
+ var parsed = [];
165
+ for (var i = 1; i < lines.length; i++) {
166
+ var handle = lines[i].split(',')[0].trim();
167
+ if (handle && handle.indexOf('@') !== -1) {
168
+ parsed.push(handle);
169
+ }
170
+ }
171
+ self.handles = parsed;
157
172
  };
158
173
  reader.onerror = function() {
159
174
  self.fileError = 'Could not read file';
@@ -183,12 +198,19 @@
183
198
  return;
184
199
  }
185
200
 
201
+ if (self.handles.length === 0) {
202
+ self.importing = false;
203
+ self.resultType = 'error';
204
+ self.resultText = 'No valid handles found in the CSV file.';
205
+ return;
206
+ }
207
+
186
208
  try {
187
209
  var res = await fetch(mountPath + '/admin/migrate/import', {
188
210
  method: 'POST',
189
211
  headers: { 'Content-Type': 'application/json' },
190
212
  body: JSON.stringify({
191
- csvContent: self.csvContent,
213
+ handles: self.handles,
192
214
  importTypes: importTypes
193
215
  })
194
216
  });