@proliferate_ai/nextjs-plugin 0.1.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.
@@ -0,0 +1,187 @@
1
+ // src/sourcemap-uploader.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import { execSync } from "child_process";
5
+ import FormData from "form-data";
6
+ function log(options, message) {
7
+ if (!options.silent) {
8
+ console.log(`[Proliferate] ${message}`);
9
+ }
10
+ }
11
+ function warn(options, message) {
12
+ if (!options.silent) {
13
+ console.warn(`[Proliferate] ${message}`);
14
+ }
15
+ }
16
+ function detectRelease() {
17
+ const envVars = [
18
+ "PROLIFERATE_RELEASE",
19
+ "GITHUB_SHA",
20
+ "VERCEL_GIT_COMMIT_SHA",
21
+ "CF_PAGES_COMMIT_SHA",
22
+ "RENDER_GIT_COMMIT",
23
+ "RAILWAY_GIT_COMMIT_SHA",
24
+ "GITLAB_CI_COMMIT_SHA",
25
+ "CIRCLE_SHA1",
26
+ "COMMIT_SHA",
27
+ "GIT_COMMIT"
28
+ ];
29
+ for (const envVar of envVars) {
30
+ const value = process.env[envVar];
31
+ if (value) {
32
+ return value;
33
+ }
34
+ }
35
+ try {
36
+ const sha = execSync("git rev-parse HEAD", { encoding: "utf8" }).trim();
37
+ return sha;
38
+ } catch {
39
+ }
40
+ return `build-${Date.now()}`;
41
+ }
42
+ async function createRelease(options) {
43
+ const form = new FormData();
44
+ form.append("version", options.release);
45
+ form.append("url_prefix", options.urlPrefix || "~/_next/");
46
+ const response = await fetch(`${options.endpoint}/releases`, {
47
+ method: "POST",
48
+ headers: {
49
+ Authorization: `Bearer ${options.apiKey}`
50
+ },
51
+ body: form
52
+ });
53
+ if (!response.ok) {
54
+ const text = await response.text();
55
+ throw new Error(`Failed to create release: ${response.status} ${text}`);
56
+ }
57
+ }
58
+ async function uploadSourceMap(options, url, content) {
59
+ const form = new FormData();
60
+ form.append("release", options.release);
61
+ form.append("url", url);
62
+ form.append("url_prefix", options.urlPrefix || "~/_next/");
63
+ form.append("sourcemap", Buffer.from(content), {
64
+ filename: "sourcemap.map",
65
+ contentType: "application/json"
66
+ });
67
+ const response = await fetch(`${options.endpoint}/sourcemaps`, {
68
+ method: "POST",
69
+ headers: {
70
+ Authorization: `Bearer ${options.apiKey}`
71
+ },
72
+ body: form
73
+ });
74
+ if (!response.ok) {
75
+ const text = await response.text();
76
+ throw new Error(`${response.status} ${text}`);
77
+ }
78
+ }
79
+ async function finalizeRelease(options) {
80
+ const response = await fetch(
81
+ `${options.endpoint}/releases/${encodeURIComponent(options.release)}/finalize`,
82
+ {
83
+ method: "POST",
84
+ headers: {
85
+ Authorization: `Bearer ${options.apiKey}`
86
+ }
87
+ }
88
+ );
89
+ if (!response.ok) {
90
+ const text = await response.text();
91
+ warn(options, `Failed to finalize release: ${response.status} ${text}`);
92
+ }
93
+ }
94
+ function findMapFiles(dir, exclude = ["node_modules"]) {
95
+ const mapFiles = [];
96
+ function scan(currentDir) {
97
+ if (!fs.existsSync(currentDir)) return;
98
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
99
+ for (const entry of entries) {
100
+ const fullPath = path.join(currentDir, entry.name);
101
+ if (entry.isDirectory()) {
102
+ const shouldExclude = exclude.some((pattern) => {
103
+ if (pattern.includes("*")) {
104
+ const regex = new RegExp(pattern.replace(/\*/g, ".*"));
105
+ return regex.test(entry.name);
106
+ }
107
+ return entry.name === pattern || fullPath.includes(pattern);
108
+ });
109
+ if (!shouldExclude) {
110
+ scan(fullPath);
111
+ }
112
+ } else if (entry.name.endsWith(".map")) {
113
+ mapFiles.push(fullPath);
114
+ }
115
+ }
116
+ }
117
+ scan(dir);
118
+ return mapFiles;
119
+ }
120
+ async function uploadSourceMaps(options) {
121
+ const release = options.release || detectRelease();
122
+ const outDir = options.outDir || ".next";
123
+ const urlPrefix = options.urlPrefix || "~/_next/";
124
+ const exclude = options.exclude || ["node_modules"];
125
+ const fullOptions = { ...options, release, urlPrefix };
126
+ const outputPath = path.resolve(process.cwd(), outDir);
127
+ const staticDir = path.join(outputPath, "static");
128
+ const mapFiles = findMapFiles(staticDir, exclude);
129
+ if (mapFiles.length === 0) {
130
+ warn(fullOptions, "No source maps found to upload");
131
+ warn(fullOptions, `Looked in: ${staticDir}`);
132
+ warn(
133
+ fullOptions,
134
+ "Make sure productionBrowserSourceMaps is enabled in next.config.js"
135
+ );
136
+ return { uploaded: 0, failed: 0 };
137
+ }
138
+ log(fullOptions, `Found ${mapFiles.length} source map(s) to upload`);
139
+ log(fullOptions, `Release: ${release}`);
140
+ if (!options.dryRun) {
141
+ try {
142
+ await createRelease(fullOptions);
143
+ log(fullOptions, "Created release");
144
+ } catch (error) {
145
+ warn(fullOptions, `Failed to create release: ${error}`);
146
+ return { uploaded: 0, failed: mapFiles.length };
147
+ }
148
+ }
149
+ let uploaded = 0;
150
+ let failed = 0;
151
+ for (const mapPath of mapFiles) {
152
+ const relativePath = path.relative(staticDir, mapPath);
153
+ const minifiedFilename = relativePath.replace(".map", "");
154
+ const url = urlPrefix + "static/" + minifiedFilename;
155
+ if (options.dryRun) {
156
+ log(fullOptions, `[Dry Run] Would upload: ${url}`);
157
+ uploaded++;
158
+ continue;
159
+ }
160
+ try {
161
+ const mapContent = fs.readFileSync(mapPath, "utf8");
162
+ await uploadSourceMap(fullOptions, url, mapContent);
163
+ log(fullOptions, `Uploaded: ${url}`);
164
+ uploaded++;
165
+ if (options.deleteAfterUpload) {
166
+ fs.unlinkSync(mapPath);
167
+ log(fullOptions, `Deleted: ${relativePath}`);
168
+ }
169
+ } catch (error) {
170
+ warn(fullOptions, `Failed to upload ${relativePath}: ${error}`);
171
+ failed++;
172
+ }
173
+ }
174
+ if (!options.dryRun && uploaded > 0) {
175
+ await finalizeRelease(fullOptions);
176
+ log(fullOptions, "Finalized release");
177
+ }
178
+ log(
179
+ fullOptions,
180
+ `Source map upload complete: ${uploaded} uploaded, ${failed} failed`
181
+ );
182
+ return { uploaded, failed };
183
+ }
184
+
185
+ export {
186
+ uploadSourceMaps
187
+ };
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,340 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/sourcemap-uploader.ts
27
+ var fs = __toESM(require("fs"));
28
+ var path = __toESM(require("path"));
29
+ var import_child_process = require("child_process");
30
+ var import_form_data = __toESM(require("form-data"));
31
+ function log(options, message) {
32
+ if (!options.silent) {
33
+ console.log(`[Proliferate] ${message}`);
34
+ }
35
+ }
36
+ function warn(options, message) {
37
+ if (!options.silent) {
38
+ console.warn(`[Proliferate] ${message}`);
39
+ }
40
+ }
41
+ function detectRelease() {
42
+ const envVars = [
43
+ "PROLIFERATE_RELEASE",
44
+ "GITHUB_SHA",
45
+ "VERCEL_GIT_COMMIT_SHA",
46
+ "CF_PAGES_COMMIT_SHA",
47
+ "RENDER_GIT_COMMIT",
48
+ "RAILWAY_GIT_COMMIT_SHA",
49
+ "GITLAB_CI_COMMIT_SHA",
50
+ "CIRCLE_SHA1",
51
+ "COMMIT_SHA",
52
+ "GIT_COMMIT"
53
+ ];
54
+ for (const envVar of envVars) {
55
+ const value = process.env[envVar];
56
+ if (value) {
57
+ return value;
58
+ }
59
+ }
60
+ try {
61
+ const sha = (0, import_child_process.execSync)("git rev-parse HEAD", { encoding: "utf8" }).trim();
62
+ return sha;
63
+ } catch {
64
+ }
65
+ return `build-${Date.now()}`;
66
+ }
67
+ async function createRelease(options) {
68
+ const form = new import_form_data.default();
69
+ form.append("version", options.release);
70
+ form.append("url_prefix", options.urlPrefix || "~/_next/");
71
+ const response = await fetch(`${options.endpoint}/releases`, {
72
+ method: "POST",
73
+ headers: {
74
+ Authorization: `Bearer ${options.apiKey}`
75
+ },
76
+ body: form
77
+ });
78
+ if (!response.ok) {
79
+ const text = await response.text();
80
+ throw new Error(`Failed to create release: ${response.status} ${text}`);
81
+ }
82
+ }
83
+ async function uploadSourceMap(options, url, content) {
84
+ const form = new import_form_data.default();
85
+ form.append("release", options.release);
86
+ form.append("url", url);
87
+ form.append("url_prefix", options.urlPrefix || "~/_next/");
88
+ form.append("sourcemap", Buffer.from(content), {
89
+ filename: "sourcemap.map",
90
+ contentType: "application/json"
91
+ });
92
+ const response = await fetch(`${options.endpoint}/sourcemaps`, {
93
+ method: "POST",
94
+ headers: {
95
+ Authorization: `Bearer ${options.apiKey}`
96
+ },
97
+ body: form
98
+ });
99
+ if (!response.ok) {
100
+ const text = await response.text();
101
+ throw new Error(`${response.status} ${text}`);
102
+ }
103
+ }
104
+ async function finalizeRelease(options) {
105
+ const response = await fetch(
106
+ `${options.endpoint}/releases/${encodeURIComponent(options.release)}/finalize`,
107
+ {
108
+ method: "POST",
109
+ headers: {
110
+ Authorization: `Bearer ${options.apiKey}`
111
+ }
112
+ }
113
+ );
114
+ if (!response.ok) {
115
+ const text = await response.text();
116
+ warn(options, `Failed to finalize release: ${response.status} ${text}`);
117
+ }
118
+ }
119
+ function findMapFiles(dir, exclude = ["node_modules"]) {
120
+ const mapFiles = [];
121
+ function scan(currentDir) {
122
+ if (!fs.existsSync(currentDir)) return;
123
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
124
+ for (const entry of entries) {
125
+ const fullPath = path.join(currentDir, entry.name);
126
+ if (entry.isDirectory()) {
127
+ const shouldExclude = exclude.some((pattern) => {
128
+ if (pattern.includes("*")) {
129
+ const regex = new RegExp(pattern.replace(/\*/g, ".*"));
130
+ return regex.test(entry.name);
131
+ }
132
+ return entry.name === pattern || fullPath.includes(pattern);
133
+ });
134
+ if (!shouldExclude) {
135
+ scan(fullPath);
136
+ }
137
+ } else if (entry.name.endsWith(".map")) {
138
+ mapFiles.push(fullPath);
139
+ }
140
+ }
141
+ }
142
+ scan(dir);
143
+ return mapFiles;
144
+ }
145
+ async function uploadSourceMaps(options) {
146
+ const release = options.release || detectRelease();
147
+ const outDir = options.outDir || ".next";
148
+ const urlPrefix = options.urlPrefix || "~/_next/";
149
+ const exclude = options.exclude || ["node_modules"];
150
+ const fullOptions = { ...options, release, urlPrefix };
151
+ const outputPath = path.resolve(process.cwd(), outDir);
152
+ const staticDir = path.join(outputPath, "static");
153
+ const mapFiles = findMapFiles(staticDir, exclude);
154
+ if (mapFiles.length === 0) {
155
+ warn(fullOptions, "No source maps found to upload");
156
+ warn(fullOptions, `Looked in: ${staticDir}`);
157
+ warn(
158
+ fullOptions,
159
+ "Make sure productionBrowserSourceMaps is enabled in next.config.js"
160
+ );
161
+ return { uploaded: 0, failed: 0 };
162
+ }
163
+ log(fullOptions, `Found ${mapFiles.length} source map(s) to upload`);
164
+ log(fullOptions, `Release: ${release}`);
165
+ if (!options.dryRun) {
166
+ try {
167
+ await createRelease(fullOptions);
168
+ log(fullOptions, "Created release");
169
+ } catch (error) {
170
+ warn(fullOptions, `Failed to create release: ${error}`);
171
+ return { uploaded: 0, failed: mapFiles.length };
172
+ }
173
+ }
174
+ let uploaded = 0;
175
+ let failed = 0;
176
+ for (const mapPath of mapFiles) {
177
+ const relativePath = path.relative(staticDir, mapPath);
178
+ const minifiedFilename = relativePath.replace(".map", "");
179
+ const url = urlPrefix + "static/" + minifiedFilename;
180
+ if (options.dryRun) {
181
+ log(fullOptions, `[Dry Run] Would upload: ${url}`);
182
+ uploaded++;
183
+ continue;
184
+ }
185
+ try {
186
+ const mapContent = fs.readFileSync(mapPath, "utf8");
187
+ await uploadSourceMap(fullOptions, url, mapContent);
188
+ log(fullOptions, `Uploaded: ${url}`);
189
+ uploaded++;
190
+ if (options.deleteAfterUpload) {
191
+ fs.unlinkSync(mapPath);
192
+ log(fullOptions, `Deleted: ${relativePath}`);
193
+ }
194
+ } catch (error) {
195
+ warn(fullOptions, `Failed to upload ${relativePath}: ${error}`);
196
+ failed++;
197
+ }
198
+ }
199
+ if (!options.dryRun && uploaded > 0) {
200
+ await finalizeRelease(fullOptions);
201
+ log(fullOptions, "Finalized release");
202
+ }
203
+ log(
204
+ fullOptions,
205
+ `Source map upload complete: ${uploaded} uploaded, ${failed} failed`
206
+ );
207
+ return { uploaded, failed };
208
+ }
209
+
210
+ // src/cli.ts
211
+ function parseArgs(args) {
212
+ const result = {
213
+ command: "",
214
+ deleteAfterUpload: false,
215
+ dryRun: false,
216
+ silent: false,
217
+ help: false
218
+ };
219
+ for (let i = 0; i < args.length; i++) {
220
+ const arg = args[i];
221
+ if (arg === "upload") {
222
+ result.command = "upload";
223
+ } else if (arg === "--help" || arg === "-h") {
224
+ result.help = true;
225
+ } else if (arg === "--dry-run") {
226
+ result.dryRun = true;
227
+ } else if (arg === "--silent") {
228
+ result.silent = true;
229
+ } else if (arg === "--delete-after-upload") {
230
+ result.deleteAfterUpload = true;
231
+ } else if (arg.startsWith("--api-key=")) {
232
+ result.apiKey = arg.split("=")[1];
233
+ } else if (arg === "--api-key" && args[i + 1]) {
234
+ result.apiKey = args[++i];
235
+ } else if (arg.startsWith("--endpoint=")) {
236
+ result.endpoint = arg.split("=")[1];
237
+ } else if (arg === "--endpoint" && args[i + 1]) {
238
+ result.endpoint = args[++i];
239
+ } else if (arg.startsWith("--release=")) {
240
+ result.release = arg.split("=")[1];
241
+ } else if (arg === "--release" && args[i + 1]) {
242
+ result.release = args[++i];
243
+ } else if (arg.startsWith("--url-prefix=")) {
244
+ result.urlPrefix = arg.split("=")[1];
245
+ } else if (arg === "--url-prefix" && args[i + 1]) {
246
+ result.urlPrefix = args[++i];
247
+ } else if (arg.startsWith("--out-dir=")) {
248
+ result.outDir = arg.split("=")[1];
249
+ } else if (arg === "--out-dir" && args[i + 1]) {
250
+ result.outDir = args[++i];
251
+ }
252
+ }
253
+ result.apiKey = result.apiKey || process.env.PROLIFERATE_API_KEY;
254
+ result.endpoint = result.endpoint || process.env.PROLIFERATE_ENDPOINT;
255
+ result.release = result.release || process.env.PROLIFERATE_RELEASE;
256
+ return result;
257
+ }
258
+ function printHelp() {
259
+ console.log(`
260
+ @proliferate/nextjs-plugin - Upload Next.js source maps to Proliferate
261
+
262
+ USAGE:
263
+ npx @proliferate/nextjs-plugin upload [options]
264
+
265
+ COMMANDS:
266
+ upload Upload source maps to Proliferate
267
+
268
+ OPTIONS:
269
+ --api-key=KEY Proliferate API key (or PROLIFERATE_API_KEY env var)
270
+ --endpoint=URL Proliferate API endpoint (or PROLIFERATE_ENDPOINT env var)
271
+ --release=VERSION Release version (auto-detected from git/CI if not specified)
272
+ --url-prefix=PREFIX URL prefix for source maps (default: ~/_next/)
273
+ --out-dir=DIR Next.js output directory (default: .next)
274
+ --delete-after-upload Delete source maps after uploading
275
+ --dry-run Show what would be uploaded without actually uploading
276
+ --silent Suppress log output
277
+ --help, -h Show this help message
278
+
279
+ EXAMPLES:
280
+ # Basic upload
281
+ npx @proliferate/nextjs-plugin upload \\
282
+ --api-key=$PROLIFERATE_API_KEY \\
283
+ --endpoint=https://api.proliferate.com
284
+
285
+ # Dry run to see what would be uploaded
286
+ npx @proliferate/nextjs-plugin upload --dry-run
287
+
288
+ # Upload and delete source maps afterward (for security)
289
+ npx @proliferate/nextjs-plugin upload --delete-after-upload
290
+
291
+ ENVIRONMENT VARIABLES:
292
+ PROLIFERATE_API_KEY API key (alternative to --api-key)
293
+ PROLIFERATE_ENDPOINT API endpoint (alternative to --endpoint)
294
+ PROLIFERATE_RELEASE Release version (alternative to --release)
295
+ `);
296
+ }
297
+ async function main() {
298
+ const args = parseArgs(process.argv.slice(2));
299
+ if (args.help || !args.command) {
300
+ printHelp();
301
+ process.exit(args.help ? 0 : 1);
302
+ }
303
+ if (args.command === "upload") {
304
+ if (!args.apiKey) {
305
+ console.error(
306
+ "Error: API key is required. Use --api-key or set PROLIFERATE_API_KEY environment variable."
307
+ );
308
+ process.exit(1);
309
+ }
310
+ if (!args.endpoint) {
311
+ console.error(
312
+ "Error: Endpoint is required. Use --endpoint or set PROLIFERATE_ENDPOINT environment variable."
313
+ );
314
+ process.exit(1);
315
+ }
316
+ try {
317
+ const result = await uploadSourceMaps({
318
+ apiKey: args.apiKey,
319
+ endpoint: args.endpoint,
320
+ release: args.release,
321
+ urlPrefix: args.urlPrefix,
322
+ outDir: args.outDir,
323
+ deleteAfterUpload: args.deleteAfterUpload,
324
+ dryRun: args.dryRun,
325
+ silent: args.silent
326
+ });
327
+ if (result.failed > 0) {
328
+ process.exit(1);
329
+ }
330
+ } catch (error) {
331
+ console.error("Error:", error);
332
+ process.exit(1);
333
+ }
334
+ } else {
335
+ console.error(`Unknown command: ${args.command}`);
336
+ printHelp();
337
+ process.exit(1);
338
+ }
339
+ }
340
+ main();
package/dist/cli.mjs ADDED
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ uploadSourceMaps
4
+ } from "./chunk-PPXY4MSU.mjs";
5
+
6
+ // src/cli.ts
7
+ function parseArgs(args) {
8
+ const result = {
9
+ command: "",
10
+ deleteAfterUpload: false,
11
+ dryRun: false,
12
+ silent: false,
13
+ help: false
14
+ };
15
+ for (let i = 0; i < args.length; i++) {
16
+ const arg = args[i];
17
+ if (arg === "upload") {
18
+ result.command = "upload";
19
+ } else if (arg === "--help" || arg === "-h") {
20
+ result.help = true;
21
+ } else if (arg === "--dry-run") {
22
+ result.dryRun = true;
23
+ } else if (arg === "--silent") {
24
+ result.silent = true;
25
+ } else if (arg === "--delete-after-upload") {
26
+ result.deleteAfterUpload = true;
27
+ } else if (arg.startsWith("--api-key=")) {
28
+ result.apiKey = arg.split("=")[1];
29
+ } else if (arg === "--api-key" && args[i + 1]) {
30
+ result.apiKey = args[++i];
31
+ } else if (arg.startsWith("--endpoint=")) {
32
+ result.endpoint = arg.split("=")[1];
33
+ } else if (arg === "--endpoint" && args[i + 1]) {
34
+ result.endpoint = args[++i];
35
+ } else if (arg.startsWith("--release=")) {
36
+ result.release = arg.split("=")[1];
37
+ } else if (arg === "--release" && args[i + 1]) {
38
+ result.release = args[++i];
39
+ } else if (arg.startsWith("--url-prefix=")) {
40
+ result.urlPrefix = arg.split("=")[1];
41
+ } else if (arg === "--url-prefix" && args[i + 1]) {
42
+ result.urlPrefix = args[++i];
43
+ } else if (arg.startsWith("--out-dir=")) {
44
+ result.outDir = arg.split("=")[1];
45
+ } else if (arg === "--out-dir" && args[i + 1]) {
46
+ result.outDir = args[++i];
47
+ }
48
+ }
49
+ result.apiKey = result.apiKey || process.env.PROLIFERATE_API_KEY;
50
+ result.endpoint = result.endpoint || process.env.PROLIFERATE_ENDPOINT;
51
+ result.release = result.release || process.env.PROLIFERATE_RELEASE;
52
+ return result;
53
+ }
54
+ function printHelp() {
55
+ console.log(`
56
+ @proliferate/nextjs-plugin - Upload Next.js source maps to Proliferate
57
+
58
+ USAGE:
59
+ npx @proliferate/nextjs-plugin upload [options]
60
+
61
+ COMMANDS:
62
+ upload Upload source maps to Proliferate
63
+
64
+ OPTIONS:
65
+ --api-key=KEY Proliferate API key (or PROLIFERATE_API_KEY env var)
66
+ --endpoint=URL Proliferate API endpoint (or PROLIFERATE_ENDPOINT env var)
67
+ --release=VERSION Release version (auto-detected from git/CI if not specified)
68
+ --url-prefix=PREFIX URL prefix for source maps (default: ~/_next/)
69
+ --out-dir=DIR Next.js output directory (default: .next)
70
+ --delete-after-upload Delete source maps after uploading
71
+ --dry-run Show what would be uploaded without actually uploading
72
+ --silent Suppress log output
73
+ --help, -h Show this help message
74
+
75
+ EXAMPLES:
76
+ # Basic upload
77
+ npx @proliferate/nextjs-plugin upload \\
78
+ --api-key=$PROLIFERATE_API_KEY \\
79
+ --endpoint=https://api.proliferate.com
80
+
81
+ # Dry run to see what would be uploaded
82
+ npx @proliferate/nextjs-plugin upload --dry-run
83
+
84
+ # Upload and delete source maps afterward (for security)
85
+ npx @proliferate/nextjs-plugin upload --delete-after-upload
86
+
87
+ ENVIRONMENT VARIABLES:
88
+ PROLIFERATE_API_KEY API key (alternative to --api-key)
89
+ PROLIFERATE_ENDPOINT API endpoint (alternative to --endpoint)
90
+ PROLIFERATE_RELEASE Release version (alternative to --release)
91
+ `);
92
+ }
93
+ async function main() {
94
+ const args = parseArgs(process.argv.slice(2));
95
+ if (args.help || !args.command) {
96
+ printHelp();
97
+ process.exit(args.help ? 0 : 1);
98
+ }
99
+ if (args.command === "upload") {
100
+ if (!args.apiKey) {
101
+ console.error(
102
+ "Error: API key is required. Use --api-key or set PROLIFERATE_API_KEY environment variable."
103
+ );
104
+ process.exit(1);
105
+ }
106
+ if (!args.endpoint) {
107
+ console.error(
108
+ "Error: Endpoint is required. Use --endpoint or set PROLIFERATE_ENDPOINT environment variable."
109
+ );
110
+ process.exit(1);
111
+ }
112
+ try {
113
+ const result = await uploadSourceMaps({
114
+ apiKey: args.apiKey,
115
+ endpoint: args.endpoint,
116
+ release: args.release,
117
+ urlPrefix: args.urlPrefix,
118
+ outDir: args.outDir,
119
+ deleteAfterUpload: args.deleteAfterUpload,
120
+ dryRun: args.dryRun,
121
+ silent: args.silent
122
+ });
123
+ if (result.failed > 0) {
124
+ process.exit(1);
125
+ }
126
+ } catch (error) {
127
+ console.error("Error:", error);
128
+ process.exit(1);
129
+ }
130
+ } else {
131
+ console.error(`Unknown command: ${args.command}`);
132
+ printHelp();
133
+ process.exit(1);
134
+ }
135
+ }
136
+ main();
@@ -0,0 +1,150 @@
1
+ import { NextConfig } from 'next';
2
+
3
+ /**
4
+ * Source map upload utilities for Proliferate.
5
+ *
6
+ * This module handles uploading source maps to the Proliferate API.
7
+ * Used by both the Next.js plugin and the CLI.
8
+ */
9
+ /**
10
+ * Options for uploading source maps.
11
+ */
12
+ interface UploadOptions {
13
+ /**
14
+ * Your Proliferate API key.
15
+ */
16
+ apiKey: string;
17
+ /**
18
+ * The Proliferate API endpoint.
19
+ */
20
+ endpoint: string;
21
+ /**
22
+ * Release version.
23
+ */
24
+ release: string;
25
+ /**
26
+ * URL prefix for source map URLs. Defaults to '~/_next/'.
27
+ */
28
+ urlPrefix?: string;
29
+ /**
30
+ * Patterns to exclude from upload. Defaults to ['node_modules'].
31
+ */
32
+ exclude?: string[];
33
+ /**
34
+ * Delete source maps after upload. Defaults to false.
35
+ */
36
+ deleteAfterUpload?: boolean;
37
+ /**
38
+ * Suppress log output.
39
+ */
40
+ silent?: boolean;
41
+ /**
42
+ * Dry run mode - log what would be uploaded without actually uploading.
43
+ */
44
+ dryRun?: boolean;
45
+ /**
46
+ * Output directory to scan for source maps. Defaults to '.next'.
47
+ */
48
+ outDir?: string;
49
+ }
50
+ /**
51
+ * Upload source maps to the Proliferate API.
52
+ *
53
+ * @example
54
+ * ```javascript
55
+ * const { uploadSourceMaps } = require('@proliferate/nextjs-plugin');
56
+ *
57
+ * await uploadSourceMaps({
58
+ * apiKey: process.env.PROLIFERATE_API_KEY,
59
+ * endpoint: 'https://api.proliferate.com',
60
+ * release: process.env.VERCEL_GIT_COMMIT_SHA,
61
+ * });
62
+ * ```
63
+ */
64
+ declare function uploadSourceMaps(options: Omit<UploadOptions, 'release'> & {
65
+ release?: string;
66
+ }): Promise<{
67
+ uploaded: number;
68
+ failed: number;
69
+ }>;
70
+
71
+ /**
72
+ * Proliferate Next.js Plugin
73
+ *
74
+ * Integrates Proliferate error monitoring with Next.js applications by:
75
+ * 1. Injecting the release version into the build
76
+ * 2. Enabling production source maps
77
+ * 3. Providing a CLI for uploading source maps
78
+ *
79
+ * @example
80
+ * ```javascript
81
+ * // next.config.js
82
+ * const { withProliferate } = require('@proliferate/nextjs-plugin');
83
+ *
84
+ * module.exports = withProliferate({
85
+ * // your Next.js config
86
+ * }, {
87
+ * apiKey: process.env.PROLIFERATE_API_KEY,
88
+ * endpoint: 'https://api.proliferate.com',
89
+ * });
90
+ * ```
91
+ */
92
+
93
+ /**
94
+ * Configuration options for the Proliferate Next.js plugin.
95
+ */
96
+ interface ProliferateNextOptions {
97
+ /**
98
+ * Your Proliferate API key.
99
+ * Can also be set via PROLIFERATE_API_KEY environment variable.
100
+ */
101
+ apiKey?: string;
102
+ /**
103
+ * The Proliferate API endpoint.
104
+ * Can also be set via PROLIFERATE_ENDPOINT environment variable.
105
+ */
106
+ endpoint?: string;
107
+ /**
108
+ * Release version. Auto-detected from git SHA or CI environment variables if not provided.
109
+ * Can also be set via PROLIFERATE_RELEASE environment variable.
110
+ */
111
+ release?: string;
112
+ /**
113
+ * URL prefix for source map URLs. Defaults to '~/'.
114
+ */
115
+ urlPrefix?: string;
116
+ /**
117
+ * Suppress log output.
118
+ */
119
+ silent?: boolean;
120
+ /**
121
+ * Enable production source maps. Defaults to true.
122
+ * Set to false if you want to handle source map generation yourself.
123
+ */
124
+ enableSourceMaps?: boolean;
125
+ }
126
+ /**
127
+ * Wrap your Next.js config with Proliferate integration.
128
+ *
129
+ * This HOC:
130
+ * - Injects `__PROLIFERATE_RELEASE__` global variable at build time
131
+ * - Sets `NEXT_PUBLIC_PROLIFERATE_RELEASE` environment variable
132
+ * - Enables production source maps (configurable)
133
+ *
134
+ * @example
135
+ * ```javascript
136
+ * // next.config.js
137
+ * const { withProliferate } = require('@proliferate/nextjs-plugin');
138
+ *
139
+ * module.exports = withProliferate({
140
+ * reactStrictMode: true,
141
+ * // ... other Next.js config
142
+ * }, {
143
+ * apiKey: process.env.PROLIFERATE_API_KEY,
144
+ * endpoint: 'https://api.proliferate.com',
145
+ * });
146
+ * ```
147
+ */
148
+ declare function withProliferate(nextConfig?: NextConfig, options?: ProliferateNextOptions): NextConfig;
149
+
150
+ export { type ProliferateNextOptions, type UploadOptions, withProliferate as default, uploadSourceMaps, withProliferate };
@@ -0,0 +1,150 @@
1
+ import { NextConfig } from 'next';
2
+
3
+ /**
4
+ * Source map upload utilities for Proliferate.
5
+ *
6
+ * This module handles uploading source maps to the Proliferate API.
7
+ * Used by both the Next.js plugin and the CLI.
8
+ */
9
+ /**
10
+ * Options for uploading source maps.
11
+ */
12
+ interface UploadOptions {
13
+ /**
14
+ * Your Proliferate API key.
15
+ */
16
+ apiKey: string;
17
+ /**
18
+ * The Proliferate API endpoint.
19
+ */
20
+ endpoint: string;
21
+ /**
22
+ * Release version.
23
+ */
24
+ release: string;
25
+ /**
26
+ * URL prefix for source map URLs. Defaults to '~/_next/'.
27
+ */
28
+ urlPrefix?: string;
29
+ /**
30
+ * Patterns to exclude from upload. Defaults to ['node_modules'].
31
+ */
32
+ exclude?: string[];
33
+ /**
34
+ * Delete source maps after upload. Defaults to false.
35
+ */
36
+ deleteAfterUpload?: boolean;
37
+ /**
38
+ * Suppress log output.
39
+ */
40
+ silent?: boolean;
41
+ /**
42
+ * Dry run mode - log what would be uploaded without actually uploading.
43
+ */
44
+ dryRun?: boolean;
45
+ /**
46
+ * Output directory to scan for source maps. Defaults to '.next'.
47
+ */
48
+ outDir?: string;
49
+ }
50
+ /**
51
+ * Upload source maps to the Proliferate API.
52
+ *
53
+ * @example
54
+ * ```javascript
55
+ * const { uploadSourceMaps } = require('@proliferate/nextjs-plugin');
56
+ *
57
+ * await uploadSourceMaps({
58
+ * apiKey: process.env.PROLIFERATE_API_KEY,
59
+ * endpoint: 'https://api.proliferate.com',
60
+ * release: process.env.VERCEL_GIT_COMMIT_SHA,
61
+ * });
62
+ * ```
63
+ */
64
+ declare function uploadSourceMaps(options: Omit<UploadOptions, 'release'> & {
65
+ release?: string;
66
+ }): Promise<{
67
+ uploaded: number;
68
+ failed: number;
69
+ }>;
70
+
71
+ /**
72
+ * Proliferate Next.js Plugin
73
+ *
74
+ * Integrates Proliferate error monitoring with Next.js applications by:
75
+ * 1. Injecting the release version into the build
76
+ * 2. Enabling production source maps
77
+ * 3. Providing a CLI for uploading source maps
78
+ *
79
+ * @example
80
+ * ```javascript
81
+ * // next.config.js
82
+ * const { withProliferate } = require('@proliferate/nextjs-plugin');
83
+ *
84
+ * module.exports = withProliferate({
85
+ * // your Next.js config
86
+ * }, {
87
+ * apiKey: process.env.PROLIFERATE_API_KEY,
88
+ * endpoint: 'https://api.proliferate.com',
89
+ * });
90
+ * ```
91
+ */
92
+
93
+ /**
94
+ * Configuration options for the Proliferate Next.js plugin.
95
+ */
96
+ interface ProliferateNextOptions {
97
+ /**
98
+ * Your Proliferate API key.
99
+ * Can also be set via PROLIFERATE_API_KEY environment variable.
100
+ */
101
+ apiKey?: string;
102
+ /**
103
+ * The Proliferate API endpoint.
104
+ * Can also be set via PROLIFERATE_ENDPOINT environment variable.
105
+ */
106
+ endpoint?: string;
107
+ /**
108
+ * Release version. Auto-detected from git SHA or CI environment variables if not provided.
109
+ * Can also be set via PROLIFERATE_RELEASE environment variable.
110
+ */
111
+ release?: string;
112
+ /**
113
+ * URL prefix for source map URLs. Defaults to '~/'.
114
+ */
115
+ urlPrefix?: string;
116
+ /**
117
+ * Suppress log output.
118
+ */
119
+ silent?: boolean;
120
+ /**
121
+ * Enable production source maps. Defaults to true.
122
+ * Set to false if you want to handle source map generation yourself.
123
+ */
124
+ enableSourceMaps?: boolean;
125
+ }
126
+ /**
127
+ * Wrap your Next.js config with Proliferate integration.
128
+ *
129
+ * This HOC:
130
+ * - Injects `__PROLIFERATE_RELEASE__` global variable at build time
131
+ * - Sets `NEXT_PUBLIC_PROLIFERATE_RELEASE` environment variable
132
+ * - Enables production source maps (configurable)
133
+ *
134
+ * @example
135
+ * ```javascript
136
+ * // next.config.js
137
+ * const { withProliferate } = require('@proliferate/nextjs-plugin');
138
+ *
139
+ * module.exports = withProliferate({
140
+ * reactStrictMode: true,
141
+ * // ... other Next.js config
142
+ * }, {
143
+ * apiKey: process.env.PROLIFERATE_API_KEY,
144
+ * endpoint: 'https://api.proliferate.com',
145
+ * });
146
+ * ```
147
+ */
148
+ declare function withProliferate(nextConfig?: NextConfig, options?: ProliferateNextOptions): NextConfig;
149
+
150
+ export { type ProliferateNextOptions, type UploadOptions, withProliferate as default, uploadSourceMaps, withProliferate };
package/dist/index.js ADDED
@@ -0,0 +1,291 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ default: () => index_default,
34
+ uploadSourceMaps: () => uploadSourceMaps,
35
+ withProliferate: () => withProliferate
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+ var import_child_process2 = require("child_process");
39
+
40
+ // src/sourcemap-uploader.ts
41
+ var fs = __toESM(require("fs"));
42
+ var path = __toESM(require("path"));
43
+ var import_child_process = require("child_process");
44
+ var import_form_data = __toESM(require("form-data"));
45
+ function log(options, message) {
46
+ if (!options.silent) {
47
+ console.log(`[Proliferate] ${message}`);
48
+ }
49
+ }
50
+ function warn(options, message) {
51
+ if (!options.silent) {
52
+ console.warn(`[Proliferate] ${message}`);
53
+ }
54
+ }
55
+ function detectRelease() {
56
+ const envVars = [
57
+ "PROLIFERATE_RELEASE",
58
+ "GITHUB_SHA",
59
+ "VERCEL_GIT_COMMIT_SHA",
60
+ "CF_PAGES_COMMIT_SHA",
61
+ "RENDER_GIT_COMMIT",
62
+ "RAILWAY_GIT_COMMIT_SHA",
63
+ "GITLAB_CI_COMMIT_SHA",
64
+ "CIRCLE_SHA1",
65
+ "COMMIT_SHA",
66
+ "GIT_COMMIT"
67
+ ];
68
+ for (const envVar of envVars) {
69
+ const value = process.env[envVar];
70
+ if (value) {
71
+ return value;
72
+ }
73
+ }
74
+ try {
75
+ const sha = (0, import_child_process.execSync)("git rev-parse HEAD", { encoding: "utf8" }).trim();
76
+ return sha;
77
+ } catch {
78
+ }
79
+ return `build-${Date.now()}`;
80
+ }
81
+ async function createRelease(options) {
82
+ const form = new import_form_data.default();
83
+ form.append("version", options.release);
84
+ form.append("url_prefix", options.urlPrefix || "~/_next/");
85
+ const response = await fetch(`${options.endpoint}/releases`, {
86
+ method: "POST",
87
+ headers: {
88
+ Authorization: `Bearer ${options.apiKey}`
89
+ },
90
+ body: form
91
+ });
92
+ if (!response.ok) {
93
+ const text = await response.text();
94
+ throw new Error(`Failed to create release: ${response.status} ${text}`);
95
+ }
96
+ }
97
+ async function uploadSourceMap(options, url, content) {
98
+ const form = new import_form_data.default();
99
+ form.append("release", options.release);
100
+ form.append("url", url);
101
+ form.append("url_prefix", options.urlPrefix || "~/_next/");
102
+ form.append("sourcemap", Buffer.from(content), {
103
+ filename: "sourcemap.map",
104
+ contentType: "application/json"
105
+ });
106
+ const response = await fetch(`${options.endpoint}/sourcemaps`, {
107
+ method: "POST",
108
+ headers: {
109
+ Authorization: `Bearer ${options.apiKey}`
110
+ },
111
+ body: form
112
+ });
113
+ if (!response.ok) {
114
+ const text = await response.text();
115
+ throw new Error(`${response.status} ${text}`);
116
+ }
117
+ }
118
+ async function finalizeRelease(options) {
119
+ const response = await fetch(
120
+ `${options.endpoint}/releases/${encodeURIComponent(options.release)}/finalize`,
121
+ {
122
+ method: "POST",
123
+ headers: {
124
+ Authorization: `Bearer ${options.apiKey}`
125
+ }
126
+ }
127
+ );
128
+ if (!response.ok) {
129
+ const text = await response.text();
130
+ warn(options, `Failed to finalize release: ${response.status} ${text}`);
131
+ }
132
+ }
133
+ function findMapFiles(dir, exclude = ["node_modules"]) {
134
+ const mapFiles = [];
135
+ function scan(currentDir) {
136
+ if (!fs.existsSync(currentDir)) return;
137
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
138
+ for (const entry of entries) {
139
+ const fullPath = path.join(currentDir, entry.name);
140
+ if (entry.isDirectory()) {
141
+ const shouldExclude = exclude.some((pattern) => {
142
+ if (pattern.includes("*")) {
143
+ const regex = new RegExp(pattern.replace(/\*/g, ".*"));
144
+ return regex.test(entry.name);
145
+ }
146
+ return entry.name === pattern || fullPath.includes(pattern);
147
+ });
148
+ if (!shouldExclude) {
149
+ scan(fullPath);
150
+ }
151
+ } else if (entry.name.endsWith(".map")) {
152
+ mapFiles.push(fullPath);
153
+ }
154
+ }
155
+ }
156
+ scan(dir);
157
+ return mapFiles;
158
+ }
159
+ async function uploadSourceMaps(options) {
160
+ const release = options.release || detectRelease();
161
+ const outDir = options.outDir || ".next";
162
+ const urlPrefix = options.urlPrefix || "~/_next/";
163
+ const exclude = options.exclude || ["node_modules"];
164
+ const fullOptions = { ...options, release, urlPrefix };
165
+ const outputPath = path.resolve(process.cwd(), outDir);
166
+ const staticDir = path.join(outputPath, "static");
167
+ const mapFiles = findMapFiles(staticDir, exclude);
168
+ if (mapFiles.length === 0) {
169
+ warn(fullOptions, "No source maps found to upload");
170
+ warn(fullOptions, `Looked in: ${staticDir}`);
171
+ warn(
172
+ fullOptions,
173
+ "Make sure productionBrowserSourceMaps is enabled in next.config.js"
174
+ );
175
+ return { uploaded: 0, failed: 0 };
176
+ }
177
+ log(fullOptions, `Found ${mapFiles.length} source map(s) to upload`);
178
+ log(fullOptions, `Release: ${release}`);
179
+ if (!options.dryRun) {
180
+ try {
181
+ await createRelease(fullOptions);
182
+ log(fullOptions, "Created release");
183
+ } catch (error) {
184
+ warn(fullOptions, `Failed to create release: ${error}`);
185
+ return { uploaded: 0, failed: mapFiles.length };
186
+ }
187
+ }
188
+ let uploaded = 0;
189
+ let failed = 0;
190
+ for (const mapPath of mapFiles) {
191
+ const relativePath = path.relative(staticDir, mapPath);
192
+ const minifiedFilename = relativePath.replace(".map", "");
193
+ const url = urlPrefix + "static/" + minifiedFilename;
194
+ if (options.dryRun) {
195
+ log(fullOptions, `[Dry Run] Would upload: ${url}`);
196
+ uploaded++;
197
+ continue;
198
+ }
199
+ try {
200
+ const mapContent = fs.readFileSync(mapPath, "utf8");
201
+ await uploadSourceMap(fullOptions, url, mapContent);
202
+ log(fullOptions, `Uploaded: ${url}`);
203
+ uploaded++;
204
+ if (options.deleteAfterUpload) {
205
+ fs.unlinkSync(mapPath);
206
+ log(fullOptions, `Deleted: ${relativePath}`);
207
+ }
208
+ } catch (error) {
209
+ warn(fullOptions, `Failed to upload ${relativePath}: ${error}`);
210
+ failed++;
211
+ }
212
+ }
213
+ if (!options.dryRun && uploaded > 0) {
214
+ await finalizeRelease(fullOptions);
215
+ log(fullOptions, "Finalized release");
216
+ }
217
+ log(
218
+ fullOptions,
219
+ `Source map upload complete: ${uploaded} uploaded, ${failed} failed`
220
+ );
221
+ return { uploaded, failed };
222
+ }
223
+
224
+ // src/index.ts
225
+ function detectRelease2() {
226
+ const envVars = [
227
+ "PROLIFERATE_RELEASE",
228
+ "GITHUB_SHA",
229
+ "VERCEL_GIT_COMMIT_SHA",
230
+ "CF_PAGES_COMMIT_SHA",
231
+ "RENDER_GIT_COMMIT",
232
+ "RAILWAY_GIT_COMMIT_SHA",
233
+ "GITLAB_CI_COMMIT_SHA",
234
+ "CIRCLE_SHA1",
235
+ "COMMIT_SHA",
236
+ "GIT_COMMIT"
237
+ ];
238
+ for (const envVar of envVars) {
239
+ const value = process.env[envVar];
240
+ if (value) {
241
+ return value;
242
+ }
243
+ }
244
+ try {
245
+ const sha = (0, import_child_process2.execSync)("git rev-parse HEAD", { encoding: "utf8" }).trim();
246
+ return sha;
247
+ } catch {
248
+ }
249
+ return `build-${Date.now()}`;
250
+ }
251
+ function log2(options, message) {
252
+ if (!options.silent) {
253
+ console.log(`[Proliferate] ${message}`);
254
+ }
255
+ }
256
+ function withProliferate(nextConfig = {}, options = {}) {
257
+ const release = options.release || process.env.PROLIFERATE_RELEASE || detectRelease2();
258
+ const enableSourceMaps = options.enableSourceMaps !== false;
259
+ log2(options, `Using release: ${release}`);
260
+ return {
261
+ ...nextConfig,
262
+ // Inject release as public environment variable
263
+ env: {
264
+ ...nextConfig.env,
265
+ NEXT_PUBLIC_PROLIFERATE_RELEASE: release
266
+ },
267
+ // Enable source maps in production builds
268
+ ...enableSourceMaps && {
269
+ productionBrowserSourceMaps: true
270
+ },
271
+ // Extend webpack config
272
+ webpack(config, context) {
273
+ const { webpack } = context;
274
+ config.plugins.push(
275
+ new webpack.DefinePlugin({
276
+ __PROLIFERATE_RELEASE__: JSON.stringify(release)
277
+ })
278
+ );
279
+ if (typeof nextConfig.webpack === "function") {
280
+ return nextConfig.webpack(config, context);
281
+ }
282
+ return config;
283
+ }
284
+ };
285
+ }
286
+ var index_default = withProliferate;
287
+ // Annotate the CommonJS export names for ESM import in node:
288
+ 0 && (module.exports = {
289
+ uploadSourceMaps,
290
+ withProliferate
291
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,73 @@
1
+ import {
2
+ uploadSourceMaps
3
+ } from "./chunk-PPXY4MSU.mjs";
4
+
5
+ // src/index.ts
6
+ import { execSync } from "child_process";
7
+ function detectRelease() {
8
+ const envVars = [
9
+ "PROLIFERATE_RELEASE",
10
+ "GITHUB_SHA",
11
+ "VERCEL_GIT_COMMIT_SHA",
12
+ "CF_PAGES_COMMIT_SHA",
13
+ "RENDER_GIT_COMMIT",
14
+ "RAILWAY_GIT_COMMIT_SHA",
15
+ "GITLAB_CI_COMMIT_SHA",
16
+ "CIRCLE_SHA1",
17
+ "COMMIT_SHA",
18
+ "GIT_COMMIT"
19
+ ];
20
+ for (const envVar of envVars) {
21
+ const value = process.env[envVar];
22
+ if (value) {
23
+ return value;
24
+ }
25
+ }
26
+ try {
27
+ const sha = execSync("git rev-parse HEAD", { encoding: "utf8" }).trim();
28
+ return sha;
29
+ } catch {
30
+ }
31
+ return `build-${Date.now()}`;
32
+ }
33
+ function log(options, message) {
34
+ if (!options.silent) {
35
+ console.log(`[Proliferate] ${message}`);
36
+ }
37
+ }
38
+ function withProliferate(nextConfig = {}, options = {}) {
39
+ const release = options.release || process.env.PROLIFERATE_RELEASE || detectRelease();
40
+ const enableSourceMaps = options.enableSourceMaps !== false;
41
+ log(options, `Using release: ${release}`);
42
+ return {
43
+ ...nextConfig,
44
+ // Inject release as public environment variable
45
+ env: {
46
+ ...nextConfig.env,
47
+ NEXT_PUBLIC_PROLIFERATE_RELEASE: release
48
+ },
49
+ // Enable source maps in production builds
50
+ ...enableSourceMaps && {
51
+ productionBrowserSourceMaps: true
52
+ },
53
+ // Extend webpack config
54
+ webpack(config, context) {
55
+ const { webpack } = context;
56
+ config.plugins.push(
57
+ new webpack.DefinePlugin({
58
+ __PROLIFERATE_RELEASE__: JSON.stringify(release)
59
+ })
60
+ );
61
+ if (typeof nextConfig.webpack === "function") {
62
+ return nextConfig.webpack(config, context);
63
+ }
64
+ return config;
65
+ }
66
+ };
67
+ }
68
+ var index_default = withProliferate;
69
+ export {
70
+ index_default as default,
71
+ uploadSourceMaps,
72
+ withProliferate
73
+ };
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@proliferate_ai/nextjs-plugin",
3
+ "version": "0.1.0",
4
+ "description": "Proliferate integration for Next.js - source map upload and release tracking",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "proliferate-nextjs": "./dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --clean",
23
+ "dev": "tsup src/index.ts src/cli.ts --format cjs,esm --dts --watch",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "typecheck": "tsc --noEmit"
27
+ },
28
+ "keywords": [
29
+ "nextjs",
30
+ "next",
31
+ "sourcemaps",
32
+ "error-monitoring",
33
+ "proliferate"
34
+ ],
35
+ "author": "",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/YOUR_ORG/proliferation.git",
40
+ "directory": "sdks/nextjs-plugin"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public",
44
+ "provenance": true
45
+ },
46
+ "dependencies": {
47
+ "form-data": "^4.0.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^20.19.27",
51
+ "next": "^14.0.0 || ^15.0.0",
52
+ "tsup": "^8.0.0",
53
+ "typescript": "^5.0.0",
54
+ "vitest": "^4.0.16"
55
+ },
56
+ "peerDependencies": {
57
+ "next": ">=12.0.0"
58
+ },
59
+ "engines": {
60
+ "node": ">=18"
61
+ }
62
+ }