@interfere/next 1.0.5 → 4.0.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/config.d.mts +11 -1
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +28 -40
- package/dist/config.mjs.map +1 -1
- package/dist/internal/build/pipeline.d.mts +49 -0
- package/dist/internal/build/pipeline.d.mts.map +1 -0
- package/dist/internal/build/pipeline.mjs +67 -0
- package/dist/internal/build/pipeline.mjs.map +1 -0
- package/dist/internal/build/release/destinations/vercel.d.mts +1 -1
- package/dist/internal/build/release/destinations/vercel.mjs +2 -2
- package/dist/internal/build/release/destinations/vercel.mjs.map +1 -1
- package/dist/internal/build/release/index.d.mts +4 -3
- package/dist/internal/build/release/index.d.mts.map +1 -1
- package/dist/internal/build/release/index.mjs +8 -14
- package/dist/internal/build/release/index.mjs.map +1 -1
- package/dist/internal/build/source-maps/discover.mjs +1 -1
- package/dist/internal/build/source-maps/index.d.mts +23 -20
- package/dist/internal/build/source-maps/index.d.mts.map +1 -1
- package/dist/internal/build/source-maps/index.mjs +21 -27
- package/dist/internal/build/source-maps/index.mjs.map +1 -1
- package/dist/internal/env.mjs.map +1 -1
- package/dist/internal/logger.d.mts +1 -0
- package/dist/internal/logger.d.mts.map +1 -1
- package/dist/internal/logger.mjs +23 -7
- package/dist/internal/logger.mjs.map +1 -1
- package/dist/internal/route/handle-post.mjs +4 -2
- package/dist/internal/route/handle-post.mjs.map +1 -1
- package/dist/internal/route/sw-script.d.mts +1 -1
- package/dist/internal/route/sw-script.mjs +1 -1
- package/dist/internal/route/sw-script.mjs.map +1 -1
- package/package.json +9 -10
package/dist/config.d.mts
CHANGED
|
@@ -6,6 +6,16 @@ interface InterfereConfig extends Partial<Pick<Envelope, "buildId" | "releaseId"
|
|
|
6
6
|
interface NextConfigWithInterfere extends NextConfig {
|
|
7
7
|
interfere?: InterfereConfig;
|
|
8
8
|
}
|
|
9
|
+
interface ResolvedBuildConfig {
|
|
10
|
+
readonly apiKey: string | null;
|
|
11
|
+
readonly apiUrl: string;
|
|
12
|
+
readonly buildId: string | null;
|
|
13
|
+
readonly releaseId: string | null;
|
|
14
|
+
}
|
|
9
15
|
declare function withInterfere(nextConfig?: NextConfigWithInterfere): NextConfig;
|
|
16
|
+
interface ProductionCompileContext {
|
|
17
|
+
readonly distDir: string;
|
|
18
|
+
readonly projectDir: string;
|
|
19
|
+
}
|
|
10
20
|
//#endregion
|
|
11
|
-
export { InterfereConfig, NextConfigWithInterfere, withInterfere };
|
|
21
|
+
export { InterfereConfig, NextConfigWithInterfere, ProductionCompileContext, ResolvedBuildConfig, withInterfere };
|
package/dist/config.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;;UAeiB,eAAA,SACP,OAAA,CAAQ,IAAA,CAAK,QAAA;AAAA,UAEN,uBAAA,SAAgC,UAAA;EAC/C,SAAA,GAAY,eAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;;UAeiB,eAAA,SACP,OAAA,CAAQ,IAAA,CAAK,QAAA;AAAA,UAEN,uBAAA,SAAgC,UAAA;EAC/C,SAAA,GAAY,eAAA;AAAA;AAAA,UAGG,mBAAA;EAAA,SACN,MAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;AAAA;AAAA,iBAGK,aAAA,CACd,UAAA,GAAY,uBAAA,GACX,UAAA;AAAA,UAqFc,wBAAA;EAAA,SACN,OAAA;EAAA,SACA,UAAA;AAAA"}
|
package/dist/config.mjs
CHANGED
|
@@ -18,7 +18,7 @@ function withInterfere(nextConfig = {}) {
|
|
|
18
18
|
__INTERFERE_RELEASE_ID__: config.releaseId
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
|
-
if (config.apiKey !== null && !build.webpack && !build.turbopack)
|
|
21
|
+
if (config.apiKey !== null && !build.webpack && !build.turbopack) return log.fatal("Missing instrumentation client", ["INTERFERE_API_KEY is set but no instrumentation-client file was found.", "Create an instrumentation-client.ts file in your project root or src/ directory."]);
|
|
22
22
|
const existingHook = compiler?.runAfterProductionCompile;
|
|
23
23
|
return {
|
|
24
24
|
...rest,
|
|
@@ -38,11 +38,12 @@ function withInterfere(nextConfig = {}) {
|
|
|
38
38
|
function resolveBuildConfig(interfere) {
|
|
39
39
|
const { apiKey, apiUrl } = readInterfereEnv();
|
|
40
40
|
const buildId = parseEnvValue(interfere?.buildId) ?? readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ?? runGitCommand("git rev-parse HEAD");
|
|
41
|
+
const releaseId = parseEnvValue(interfere?.releaseId) ?? readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ?? buildId;
|
|
41
42
|
return {
|
|
42
|
-
apiKey,
|
|
43
|
+
apiKey: apiKey ?? null,
|
|
43
44
|
apiUrl,
|
|
44
45
|
buildId,
|
|
45
|
-
releaseId
|
|
46
|
+
releaseId
|
|
46
47
|
};
|
|
47
48
|
}
|
|
48
49
|
function mergeEnvConfig(userEnv, config) {
|
|
@@ -54,57 +55,44 @@ function mergeEnvConfig(userEnv, config) {
|
|
|
54
55
|
...userEnv
|
|
55
56
|
};
|
|
56
57
|
}
|
|
58
|
+
function isNetworkError(error) {
|
|
59
|
+
if (error instanceof TypeError) return true;
|
|
60
|
+
if (error instanceof Error) {
|
|
61
|
+
const msg = error.message.toLowerCase();
|
|
62
|
+
return msg.includes("econnrefused") || msg.includes("enotfound") || msg.includes("fetch failed") || msg.includes("network");
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
57
66
|
async function runBuildReleasePipeline(context, config) {
|
|
58
67
|
const { apiKey, apiUrl, buildId } = config;
|
|
59
|
-
if (apiKey
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
const { createRelease } = await import("./internal/build/release/index.mjs");
|
|
69
|
-
const { runSourceMapPipeline } = await import("./internal/build/source-maps/index.mjs");
|
|
70
|
-
const client = {
|
|
71
|
-
async createRelease() {
|
|
72
|
-
const release = await createRelease(apiKey, apiUrl, buildId);
|
|
73
|
-
return {
|
|
74
|
-
slug: release.destination.slug,
|
|
75
|
-
orgSlug: release.org.slug,
|
|
76
|
-
buildId: release.build.hash ?? buildId
|
|
77
|
-
};
|
|
78
|
-
},
|
|
79
|
-
async uploadSourceMaps(releaseSlug, body) {
|
|
80
|
-
const url = `${apiUrl}/v1/releases/${releaseSlug}/source-maps`;
|
|
81
|
-
const response = await fetch(url, {
|
|
82
|
-
method: "POST",
|
|
83
|
-
headers: { "x-api-key": apiKey },
|
|
84
|
-
body
|
|
85
|
-
});
|
|
86
|
-
if (!response.ok) {
|
|
87
|
-
const text = await response.text().catch(() => "");
|
|
88
|
-
throw new Error(`Source map upload failed: ${response.status} ${response.statusText} ${text}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
68
|
+
if (!apiKey) return log.fatal("API key not set", [
|
|
69
|
+
"withInterfere() requires an API key to upload source maps during production builds.",
|
|
70
|
+
"Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.",
|
|
71
|
+
"See: https://interfere.com/docs/nextjs/setup"
|
|
72
|
+
]);
|
|
73
|
+
if (!buildId) return log.fatal("Build ID missing", ["Could not resolve a build ID from config, environment variables, or git.", "Set INTERFERE_BUILD_ID, or ensure git is available in your build environment."]);
|
|
74
|
+
const { runBuildPipeline } = await import("./internal/build/pipeline.mjs");
|
|
92
75
|
try {
|
|
93
|
-
const result = await
|
|
76
|
+
const result = await runBuildPipeline(context, {
|
|
77
|
+
...config,
|
|
78
|
+
apiKey,
|
|
79
|
+
buildId
|
|
80
|
+
});
|
|
94
81
|
if (!result.ready) {
|
|
95
82
|
log.warn("Skipping", ["No source maps found"]);
|
|
96
83
|
return;
|
|
97
84
|
}
|
|
98
85
|
log.info("Completed", [
|
|
99
|
-
`https://interfere.com/~/${result.
|
|
100
|
-
`Release: ${result.
|
|
86
|
+
`https://interfere.com/~/${result.config?.org.slug}/surfaces/${result.config?.surface.slug}`,
|
|
87
|
+
`Release: ${result.release?.destination.slug ?? "Unknown"}`,
|
|
101
88
|
`Build: ${result.buildId}`,
|
|
102
89
|
`Artifacts: ${result.fileCount} source maps`
|
|
103
90
|
]);
|
|
104
91
|
} catch (error) {
|
|
105
92
|
const message = error instanceof Error ? error.message : String(error);
|
|
106
93
|
if (apiUrl !== API_URL) {
|
|
107
|
-
|
|
94
|
+
const isNetwork = isNetworkError(error);
|
|
95
|
+
log.warn("Skipping release pipeline", [message, isNetwork ? `${apiUrl} is unreachable — this is expected during local development.` : `${apiUrl} returned an error. Ensure the collector is running and configured correctly.`]);
|
|
108
96
|
return;
|
|
109
97
|
}
|
|
110
98
|
log.error("Error", [message]);
|
package/dist/config.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport {\n releaseDestinationIdEnvKeys,\n releaseSourceIdEnvKeys,\n} from \"@interfere/types/integrations\";\nimport { parseEnvValue, readFirstEnvValue } from \"@interfere/types/sdk/env\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport type { NextConfig } from \"next\";\n\nimport { configureBuild } from \"./internal/build/configure-build.js\";\nimport { runGitCommand } from \"./internal/build/release/git.js\";\nimport { readInterfereEnv } from \"./internal/env.js\";\nimport { log } from \"./internal/logger.js\";\n\nexport interface InterfereConfig\n extends Partial<Pick<Envelope, \"buildId\" | \"releaseId\">> {}\n\nexport interface NextConfigWithInterfere extends NextConfig {\n interfere?: InterfereConfig;\n}\n\
|
|
1
|
+
{"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport {\n releaseDestinationIdEnvKeys,\n releaseSourceIdEnvKeys,\n} from \"@interfere/types/integrations\";\nimport { parseEnvValue, readFirstEnvValue } from \"@interfere/types/sdk/env\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport type { NextConfig } from \"next\";\n\nimport { configureBuild } from \"./internal/build/configure-build.js\";\nimport { runGitCommand } from \"./internal/build/release/git.js\";\nimport { readInterfereEnv } from \"./internal/env.js\";\nimport { log } from \"./internal/logger.js\";\n\nexport interface InterfereConfig\n extends Partial<Pick<Envelope, \"buildId\" | \"releaseId\">> {}\n\nexport interface NextConfigWithInterfere extends NextConfig {\n interfere?: InterfereConfig;\n}\n\nexport interface ResolvedBuildConfig {\n readonly apiKey: string | null;\n readonly apiUrl: string;\n readonly buildId: string | null;\n readonly releaseId: string | null;\n}\n\nexport function withInterfere(\n nextConfig: NextConfigWithInterfere = {}\n): NextConfig {\n const {\n interfere,\n env: userEnv,\n webpack,\n turbopack,\n compiler,\n productionBrowserSourceMaps,\n ...rest\n } = nextConfig;\n\n const config = resolveBuildConfig(interfere);\n const build = configureBuild({\n existingWebpack: webpack,\n existingTurbopack: turbopack,\n projectDir: process.cwd(),\n values: {\n __INTERFERE_BUILD_ID__: config.buildId,\n __INTERFERE_RELEASE_ID__: config.releaseId,\n },\n });\n\n if (config.apiKey !== null && !build.webpack && !build.turbopack) {\n return log.fatal(\"Missing instrumentation client\", [\n \"INTERFERE_API_KEY is set but no instrumentation-client file was found.\",\n \"Create an instrumentation-client.ts file in your project root or src/ directory.\",\n ]);\n }\n\n const existingHook = (compiler as NextCompilerWithProductionHook | undefined)\n ?.runAfterProductionCompile;\n\n return {\n ...rest,\n env: mergeEnvConfig(userEnv, config),\n compiler: {\n ...(compiler ?? {}),\n async runAfterProductionCompile(context: ProductionCompileContext) {\n if (existingHook) {\n await existingHook(context);\n }\n\n await runBuildReleasePipeline(context, config);\n },\n } as NextConfig[\"compiler\"],\n webpack: build.webpack,\n turbopack: build.turbopack,\n productionBrowserSourceMaps:\n config.apiKey === null ? productionBrowserSourceMaps : true,\n };\n}\n\nfunction resolveBuildConfig(interfere?: InterfereConfig): ResolvedBuildConfig {\n const { apiKey, apiUrl } = readInterfereEnv();\n\n const buildId =\n parseEnvValue(interfere?.buildId) ??\n readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ??\n runGitCommand(\"git rev-parse HEAD\");\n\n const releaseId =\n parseEnvValue(interfere?.releaseId) ??\n readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ??\n buildId;\n\n return { apiKey: apiKey ?? null, apiUrl, buildId, releaseId };\n}\n\nfunction mergeEnvConfig(\n userEnv: NextConfig[\"env\"] | undefined,\n config: ResolvedBuildConfig\n): NextConfig[\"env\"] {\n const merged: Record<string, string> = {};\n\n if (config.buildId !== null) {\n merged.NEXT_PUBLIC_INTERFERE_BUILD_ID = config.buildId;\n }\n\n if (config.releaseId !== null) {\n merged.NEXT_PUBLIC_INTERFERE_RELEASE_ID = config.releaseId;\n }\n\n return { ...merged, ...userEnv };\n}\n\nexport interface ProductionCompileContext {\n readonly distDir: string;\n readonly projectDir: string;\n}\n\ntype NextCompilerWithProductionHook = NonNullable<NextConfig[\"compiler\"]> & {\n runAfterProductionCompile?: (\n context: ProductionCompileContext\n ) => void | Promise<void>;\n};\n\nfunction isNetworkError(error: unknown): boolean {\n if (error instanceof TypeError) {\n return true;\n }\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n return (\n msg.includes(\"econnrefused\") ||\n msg.includes(\"enotfound\") ||\n msg.includes(\"fetch failed\") ||\n msg.includes(\"network\")\n );\n }\n return false;\n}\n\nasync function runBuildReleasePipeline(\n context: ProductionCompileContext,\n config: ResolvedBuildConfig\n): Promise<void> {\n const { apiKey, apiUrl, buildId } = config;\n\n if (!apiKey) {\n return log.fatal(\"API key not set\", [\n \"withInterfere() requires an API key to upload source maps during production builds.\",\n \"Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.\",\n \"See: https://interfere.com/docs/nextjs/setup\",\n ]);\n }\n\n if (!buildId) {\n return log.fatal(\"Build ID missing\", [\n \"Could not resolve a build ID from config, environment variables, or git.\",\n \"Set INTERFERE_BUILD_ID, or ensure git is available in your build environment.\",\n ]);\n }\n\n const { runBuildPipeline } = await import(\"./internal/build/pipeline.js\");\n\n try {\n const result = await runBuildPipeline(context, {\n ...config,\n apiKey,\n buildId,\n });\n\n if (!result.ready) {\n log.warn(\"Skipping\", [\"No source maps found\"]);\n return;\n }\n\n log.info(\"Completed\", [\n `https://interfere.com/~/${result.config?.org.slug}/surfaces/${result.config?.surface.slug}`,\n `Release: ${result.release?.destination.slug ?? \"Unknown\"}`,\n `Build: ${result.buildId}`,\n `Artifacts: ${result.fileCount} source maps`,\n ]);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (apiUrl !== API_URL) {\n const isNetwork = isNetworkError(error);\n\n log.warn(\"Skipping release pipeline\", [\n message,\n isNetwork\n ? `${apiUrl} is unreachable — this is expected during local development.`\n : `${apiUrl} returned an error. Ensure the collector is running and configured correctly.`,\n ]);\n\n return;\n }\n\n log.error(\"Error\", [message]);\n throw error;\n }\n}\n"],"mappings":";;;;;;;;AA6BA,SAAgB,cACd,aAAsC,EAAE,EAC5B;CACZ,MAAM,EACJ,WACA,KAAK,SACL,SACA,WACA,UACA,6BACA,GAAG,SACD;CAEJ,MAAM,SAAS,mBAAmB,UAAU;CAC5C,MAAM,QAAQ,eAAe;EAC3B,iBAAiB;EACjB,mBAAmB;EACnB,YAAY,QAAQ,KAAK;EACzB,QAAQ;GACN,wBAAwB,OAAO;GAC/B,0BAA0B,OAAO;GAClC;EACF,CAAC;AAEF,KAAI,OAAO,WAAW,QAAQ,CAAC,MAAM,WAAW,CAAC,MAAM,UACrD,QAAO,IAAI,MAAM,kCAAkC,CACjD,0EACA,mFACD,CAAC;CAGJ,MAAM,eAAgB,UAClB;AAEJ,QAAO;EACL,GAAG;EACH,KAAK,eAAe,SAAS,OAAO;EACpC,UAAU;GACR,GAAI,YAAY,EAAE;GAClB,MAAM,0BAA0B,SAAmC;AACjE,QAAI,aACF,OAAM,aAAa,QAAQ;AAG7B,UAAM,wBAAwB,SAAS,OAAO;;GAEjD;EACD,SAAS,MAAM;EACf,WAAW,MAAM;EACjB,6BACE,OAAO,WAAW,OAAO,8BAA8B;EAC1D;;AAGH,SAAS,mBAAmB,WAAkD;CAC5E,MAAM,EAAE,QAAQ,WAAW,kBAAkB;CAE7C,MAAM,UACJ,cAAc,WAAW,QAAQ,IACjC,kBAAkB,QAAQ,KAAK,uBAAuB,IACtD,cAAc,qBAAqB;CAErC,MAAM,YACJ,cAAc,WAAW,UAAU,IACnC,kBAAkB,QAAQ,KAAK,4BAA4B,IAC3D;AAEF,QAAO;EAAE,QAAQ,UAAU;EAAM;EAAQ;EAAS;EAAW;;AAG/D,SAAS,eACP,SACA,QACmB;CACnB,MAAM,SAAiC,EAAE;AAEzC,KAAI,OAAO,YAAY,KACrB,QAAO,iCAAiC,OAAO;AAGjD,KAAI,OAAO,cAAc,KACvB,QAAO,mCAAmC,OAAO;AAGnD,QAAO;EAAE,GAAG;EAAQ,GAAG;EAAS;;AAclC,SAAS,eAAe,OAAyB;AAC/C,KAAI,iBAAiB,UACnB,QAAO;AAET,KAAI,iBAAiB,OAAO;EAC1B,MAAM,MAAM,MAAM,QAAQ,aAAa;AACvC,SACE,IAAI,SAAS,eAAe,IAC5B,IAAI,SAAS,YAAY,IACzB,IAAI,SAAS,eAAe,IAC5B,IAAI,SAAS,UAAU;;AAG3B,QAAO;;AAGT,eAAe,wBACb,SACA,QACe;CACf,MAAM,EAAE,QAAQ,QAAQ,YAAY;AAEpC,KAAI,CAAC,OACH,QAAO,IAAI,MAAM,mBAAmB;EAClC;EACA;EACA;EACD,CAAC;AAGJ,KAAI,CAAC,QACH,QAAO,IAAI,MAAM,oBAAoB,CACnC,4EACA,gFACD,CAAC;CAGJ,MAAM,EAAE,qBAAqB,MAAM,OAAO;AAE1C,KAAI;EACF,MAAM,SAAS,MAAM,iBAAiB,SAAS;GAC7C,GAAG;GACH;GACA;GACD,CAAC;AAEF,MAAI,CAAC,OAAO,OAAO;AACjB,OAAI,KAAK,YAAY,CAAC,uBAAuB,CAAC;AAC9C;;AAGF,MAAI,KAAK,aAAa;GACpB,2BAA2B,OAAO,QAAQ,IAAI,KAAK,YAAY,OAAO,QAAQ,QAAQ;GACtF,YAAY,OAAO,SAAS,YAAY,QAAQ;GAChD,UAAU,OAAO;GACjB,cAAc,OAAO,UAAU;GAChC,CAAC;UACK,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAEtE,MAAI,WAAW,SAAS;GACtB,MAAM,YAAY,eAAe,MAAM;AAEvC,OAAI,KAAK,6BAA6B,CACpC,SACA,YACI,GAAG,OAAO,gEACV,GAAG,OAAO,+EACf,CAAC;AAEF;;AAGF,MAAI,MAAM,SAAS,CAAC,QAAQ,CAAC;AAC7B,QAAM"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ProductionCompileContext, ResolvedBuildConfig } from "../../config.mjs";
|
|
2
|
+
import * as _interfere_sdk_models_releases_create_release_response_js0 from "@interfere/sdk/models/releases-create-release-response.js";
|
|
3
|
+
import { ReleasesConfigResponse } from "@interfere/sdk/models/releases-config-response.js";
|
|
4
|
+
import { CreateReleaseResponse } from "@interfere/types/releases/definition";
|
|
5
|
+
|
|
6
|
+
//#region src/internal/build/pipeline.d.ts
|
|
7
|
+
interface BuildTiming {
|
|
8
|
+
discover: number;
|
|
9
|
+
createRelease: number;
|
|
10
|
+
upload: number;
|
|
11
|
+
cleanup: number;
|
|
12
|
+
total: number;
|
|
13
|
+
fileCount: number;
|
|
14
|
+
totalBytes: number;
|
|
15
|
+
}
|
|
16
|
+
type PipelineResult = {
|
|
17
|
+
ready: false;
|
|
18
|
+
reason: "no_source_maps";
|
|
19
|
+
fileCount: 0;
|
|
20
|
+
} | {
|
|
21
|
+
ready: true;
|
|
22
|
+
fileCount: number;
|
|
23
|
+
release: CreateReleaseResponse;
|
|
24
|
+
config: ReleasesConfigResponse;
|
|
25
|
+
buildId: string;
|
|
26
|
+
timing: BuildTiming;
|
|
27
|
+
};
|
|
28
|
+
declare function runBuildPipeline(context: ProductionCompileContext, metadata: ResolvedBuildConfig & {
|
|
29
|
+
apiKey: string;
|
|
30
|
+
buildId: string;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
ready: boolean;
|
|
33
|
+
reason: string;
|
|
34
|
+
fileCount: number;
|
|
35
|
+
release?: undefined;
|
|
36
|
+
config?: undefined;
|
|
37
|
+
buildId?: undefined;
|
|
38
|
+
timing?: undefined;
|
|
39
|
+
} | {
|
|
40
|
+
ready: true;
|
|
41
|
+
fileCount: number;
|
|
42
|
+
release: _interfere_sdk_models_releases_create_release_response_js0.ReleasesCreateReleaseResponse;
|
|
43
|
+
config: ReleasesConfigResponse;
|
|
44
|
+
buildId: string;
|
|
45
|
+
timing: BuildTiming;
|
|
46
|
+
reason?: undefined;
|
|
47
|
+
}>;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { BuildTiming, PipelineResult, runBuildPipeline };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.mts","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"mappings":";;;;;;UAaiB,WAAA;EACf,QAAA;EACA,aAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA;EACA,SAAA;EACA,UAAA;AAAA;AAAA,KAGU,cAAA;EACN,KAAA;EAAc,MAAA;EAA0B,SAAA;AAAA;EACxC,KAAA;EAAa,SAAA;EAAmB,OAAA,EAAS,qBAAA;EAAuB,MAAA,EAAQ,sBAAA;EAAwB,OAAA;EAAiB,MAAA,EAAQ,WAAA;AAAA;AAAA,iBAYzG,gBAAA,CACpB,OAAA,EAAS,wBAAA,EACT,QAAA,EAAU,mBAAA;EAAwB,MAAA;EAAgB,OAAA;AAAA,IAAiB,OAAA;;;;;;;;;;;WAAtC,0DAAA,CAAA,6BAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { resolveReleaseRequest } from "./release/index.mjs";
|
|
2
|
+
import { discover, normalizeDistDir } from "./source-maps/discover.mjs";
|
|
3
|
+
import { buildUploadBody, cleanupSourceMaps } from "./source-maps/index.mjs";
|
|
4
|
+
import { HTTPClient, Interfere } from "@interfere/sdk";
|
|
5
|
+
//#region src/internal/build/pipeline.ts
|
|
6
|
+
async function timed(fn) {
|
|
7
|
+
const start = performance.now();
|
|
8
|
+
return [await fn(), Math.round(performance.now() - start)];
|
|
9
|
+
}
|
|
10
|
+
async function fetchSurfaceConfig(sdk) {
|
|
11
|
+
return await sdk.releases.getConfig();
|
|
12
|
+
}
|
|
13
|
+
async function runBuildPipeline(context, metadata) {
|
|
14
|
+
const { apiUrl, apiKey } = metadata;
|
|
15
|
+
const httpClient = new HTTPClient();
|
|
16
|
+
httpClient.addHook("beforeRequest", (request) => {
|
|
17
|
+
const nextRequest = new Request(request);
|
|
18
|
+
nextRequest.headers.set("x-api-key", apiKey);
|
|
19
|
+
return nextRequest;
|
|
20
|
+
});
|
|
21
|
+
const sdk = new Interfere({
|
|
22
|
+
serverURL: apiUrl,
|
|
23
|
+
httpClient
|
|
24
|
+
});
|
|
25
|
+
const start = performance.now();
|
|
26
|
+
const [{ discovered, config }, discoverMs] = await timed(async () => {
|
|
27
|
+
const [discovered, config] = await Promise.all([discover(context.projectDir, normalizeDistDir(context.distDir)), fetchSurfaceConfig(sdk)]);
|
|
28
|
+
return {
|
|
29
|
+
discovered,
|
|
30
|
+
config
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
if (discovered.files.length === 0) return {
|
|
34
|
+
ready: false,
|
|
35
|
+
reason: "no_source_maps",
|
|
36
|
+
fileCount: 0
|
|
37
|
+
};
|
|
38
|
+
const releaseRequest = resolveReleaseRequest(metadata.buildId, config);
|
|
39
|
+
const [release, createReleaseMs] = await timed(() => sdk.releases.create(releaseRequest));
|
|
40
|
+
const releaseSlug = release.destination.slug;
|
|
41
|
+
const buildId = release.build.hash ?? metadata.buildId;
|
|
42
|
+
const { body, totalBytes } = buildUploadBody(discovered);
|
|
43
|
+
const [, uploadMs] = await timed(() => sdk.sourceMaps.uploadMultipart({
|
|
44
|
+
releaseSlug,
|
|
45
|
+
body
|
|
46
|
+
}));
|
|
47
|
+
const [, cleanupMs] = await timed(() => cleanupSourceMaps(discovered.files));
|
|
48
|
+
const timing = {
|
|
49
|
+
discover: discoverMs,
|
|
50
|
+
createRelease: createReleaseMs,
|
|
51
|
+
upload: uploadMs,
|
|
52
|
+
cleanup: cleanupMs,
|
|
53
|
+
total: Math.round(performance.now() - start),
|
|
54
|
+
fileCount: discovered.files.length,
|
|
55
|
+
totalBytes
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
ready: true,
|
|
59
|
+
fileCount: discovered.files.length,
|
|
60
|
+
release,
|
|
61
|
+
config,
|
|
62
|
+
buildId,
|
|
63
|
+
timing
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { runBuildPipeline };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.mjs","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"sourcesContent":["import { HTTPClient, Interfere } from \"@interfere/sdk\";\n\nimport { resolveReleaseRequest } from \"./release/index.js\";\nimport {\n buildUploadBody,\n cleanupSourceMaps,\n discover,\n normalizeDistDir,\n} from \"./source-maps/index.js\";\nimport type { ProductionCompileContext, ResolvedBuildConfig } from \"../../config.js\";\nimport type { ReleasesConfigResponse } from \"@interfere/sdk/models/releases-config-response.js\";\nimport type { CreateReleaseResponse } from \"@interfere/types/releases/definition\";\n\nexport interface BuildTiming {\n discover: number;\n createRelease: number;\n upload: number;\n cleanup: number;\n total: number;\n fileCount: number;\n totalBytes: number;\n}\n\nexport type PipelineResult =\n | { ready: false; reason: \"no_source_maps\"; fileCount: 0 }\n | { ready: true; fileCount: number; release: CreateReleaseResponse; config: ReleasesConfigResponse; buildId: string; timing: BuildTiming };\n\nasync function timed<T>(fn: () => Promise<T>): Promise<[T, number]> {\n const start = performance.now();\n const result = await fn();\n return [result, Math.round(performance.now() - start)];\n}\n\nasync function fetchSurfaceConfig(sdk: Interfere) {\n return await sdk.releases.getConfig();\n}\n\nexport async function runBuildPipeline(\n context: ProductionCompileContext,\n metadata: ResolvedBuildConfig & { apiKey: string; buildId: string }\n) {\n const { apiUrl, apiKey } = metadata;\n\n const httpClient = new HTTPClient();\n\nhttpClient.addHook(\"beforeRequest\", (request) => {\n const nextRequest = new Request(request);\n\n nextRequest.headers.set(\"x-api-key\", apiKey);\n\n return nextRequest;\n});\n\n const sdk = new Interfere({ serverURL: apiUrl, httpClient });\n\n\n const start = performance.now();\n\n const [{ discovered, config }, discoverMs] = await timed(async () => {\n const [discovered, config] = await Promise.all([\n discover(context.projectDir, normalizeDistDir(context.distDir)),\n fetchSurfaceConfig(sdk),\n ]);\n return { discovered, config };\n });\n\n if (discovered.files.length === 0) {\n return { ready: false, reason: \"no_source_maps\", fileCount: 0 };\n }\n\n\n const releaseRequest = resolveReleaseRequest(\n metadata.buildId,\n config,\n );\n\n const [release, createReleaseMs] = await timed(() =>\n sdk.releases.create(releaseRequest)\n );\n\n const releaseSlug = release.destination.slug;\n const buildId = release.build.hash ?? metadata.buildId;\n\n const { body, totalBytes } = buildUploadBody(discovered);\n\n const [, uploadMs] = await timed(() =>\n sdk.sourceMaps.uploadMultipart({ releaseSlug, body })\n );\n\n const [, cleanupMs] = await timed(() => cleanupSourceMaps(discovered.files));\n\n const timing: BuildTiming = {\n discover: discoverMs,\n createRelease: createReleaseMs,\n upload: uploadMs,\n cleanup: cleanupMs,\n total: Math.round(performance.now() - start),\n fileCount: discovered.files.length,\n totalBytes,\n };\n\n return { ready: true, fileCount: discovered.files.length, release, config, buildId, timing } satisfies PipelineResult;\n}\n"],"mappings":";;;;;AA2BA,eAAe,MAAS,IAA4C;CAClE,MAAM,QAAQ,YAAY,KAAK;AAE/B,QAAO,CADQ,MAAM,IAAI,EACT,KAAK,MAAM,YAAY,KAAK,GAAG,MAAM,CAAC;;AAGxD,eAAe,mBAAmB,KAAgB;AAChD,QAAO,MAAM,IAAI,SAAS,WAAW;;AAGvC,eAAsB,iBACpB,SACA,UACA;CACA,MAAM,EAAE,QAAQ,WAAW;CAE3B,MAAM,aAAa,IAAI,YAAY;AAErC,YAAW,QAAQ,kBAAkB,YAAY;EAC/C,MAAM,cAAc,IAAI,QAAQ,QAAQ;AAExC,cAAY,QAAQ,IAAI,aAAa,OAAO;AAE5C,SAAO;GACP;CAEA,MAAM,MAAM,IAAI,UAAU;EAAE,WAAW;EAAQ;EAAY,CAAC;CAG5D,MAAM,QAAQ,YAAY,KAAK;CAE/B,MAAM,CAAC,EAAE,YAAY,UAAU,cAAc,MAAM,MAAM,YAAY;EACnE,MAAM,CAAC,YAAY,UAAU,MAAM,QAAQ,IAAI,CAC7C,SAAS,QAAQ,YAAY,iBAAiB,QAAQ,QAAQ,CAAC,EAC/D,mBAAmB,IAAI,CACxB,CAAC;AACF,SAAO;GAAE;GAAY;GAAQ;GAC7B;AAEF,KAAI,WAAW,MAAM,WAAW,EAC9B,QAAO;EAAE,OAAO;EAAO,QAAQ;EAAkB,WAAW;EAAG;CAIjE,MAAM,iBAAiB,sBACrB,SAAS,SACT,OACD;CAED,MAAM,CAAC,SAAS,mBAAmB,MAAM,YACvC,IAAI,SAAS,OAAO,eAAe,CACpC;CAED,MAAM,cAAc,QAAQ,YAAY;CACxC,MAAM,UAAU,QAAQ,MAAM,QAAQ,SAAS;CAE/C,MAAM,EAAE,MAAM,eAAe,gBAAgB,WAAW;CAExD,MAAM,GAAG,YAAY,MAAM,YACzB,IAAI,WAAW,gBAAgB;EAAE;EAAa;EAAM,CAAC,CACtD;CAED,MAAM,GAAG,aAAa,MAAM,YAAY,kBAAkB,WAAW,MAAM,CAAC;CAE5E,MAAM,SAAsB;EAC1B,UAAU;EACV,eAAe;EACf,QAAQ;EACR,SAAS;EACT,OAAO,KAAK,MAAM,YAAY,KAAK,GAAG,MAAM;EAC5C,WAAW,WAAW,MAAM;EAC5B;EACD;AAED,QAAO;EAAE,OAAO;EAAM,WAAW,WAAW,MAAM;EAAQ;EAAS;EAAQ;EAAS;EAAQ"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReleaseDestinationMetadata } from "@interfere/types/integrations";
|
|
2
2
|
|
|
3
3
|
//#region src/internal/build/release/destinations/vercel.d.ts
|
|
4
|
-
declare function resolve(): ReleaseDestinationMetadata
|
|
4
|
+
declare function resolve(): ReleaseDestinationMetadata;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { resolve };
|
|
@@ -3,11 +3,11 @@ import { parseEnvValue } from "@interfere/types/sdk/env";
|
|
|
3
3
|
//#region src/internal/build/release/destinations/vercel.ts
|
|
4
4
|
var vercel_exports = /* @__PURE__ */ __exportAll({ resolve: () => resolve });
|
|
5
5
|
function resolve() {
|
|
6
|
-
const deploymentId = parseEnvValue(process.env.VERCEL_DEPLOYMENT_ID);
|
|
7
6
|
const environment = parseEnvValue(process.env.VERCEL_ENV ?? process.env.VERCEL_TARGET_ENV);
|
|
8
|
-
|
|
7
|
+
const deploymentId = parseEnvValue(process.env.VERCEL_DEPLOYMENT_ID);
|
|
9
8
|
return {
|
|
10
9
|
provider: "vercel",
|
|
10
|
+
destinationReleaseId: deploymentId,
|
|
11
11
|
environment,
|
|
12
12
|
deploymentId,
|
|
13
13
|
deploymentUrl: resolveDeploymentUrl(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercel.mjs","names":[],"sources":["../../../../../src/internal/build/release/destinations/vercel.ts"],"sourcesContent":["import type { ReleaseDestinationMetadata } from \"@interfere/types/integrations\";\nimport { parseEnvValue } from \"@interfere/types/sdk/env\";\n\nexport function resolve(): ReleaseDestinationMetadata
|
|
1
|
+
{"version":3,"file":"vercel.mjs","names":[],"sources":["../../../../../src/internal/build/release/destinations/vercel.ts"],"sourcesContent":["import type { ReleaseDestinationMetadata } from \"@interfere/types/integrations\";\nimport { parseEnvValue } from \"@interfere/types/sdk/env\";\n\nexport function resolve(): ReleaseDestinationMetadata {\n const environment = parseEnvValue(\n process.env.VERCEL_ENV ?? process.env.VERCEL_TARGET_ENV,\n );\n\n const deploymentId = parseEnvValue(process.env.VERCEL_DEPLOYMENT_ID);\n\n return {\n provider: \"vercel\",\n destinationReleaseId: deploymentId,\n environment,\n deploymentId,\n deploymentUrl: resolveDeploymentUrl(),\n environmentName: environment,\n environmentTarget: environment,\n };\n}\n\nfunction resolveDeploymentUrl(): string | null {\n const deploymentUrl = parseEnvValue(process.env.VERCEL_URL);\n\n if (deploymentUrl === null) {\n return null;\n }\n\n if (\n deploymentUrl.startsWith(\"https://\") ||\n deploymentUrl.startsWith(\"http://\")\n ) {\n return deploymentUrl;\n }\n\n return `https://${deploymentUrl}`;\n}\n"],"mappings":";;;;AAGA,SAAgB,UAAsC;CACpD,MAAM,cAAc,cAClB,QAAQ,IAAI,cAAc,QAAQ,IAAI,kBACvC;CAED,MAAM,eAAe,cAAc,QAAQ,IAAI,qBAAqB;AAEpE,QAAO;EACL,UAAU;EACV,sBAAsB;EACtB;EACA;EACA,eAAe,sBAAsB;EACrC,iBAAiB;EACjB,mBAAmB;EACpB;;AAGH,SAAS,uBAAsC;CAC7C,MAAM,gBAAgB,cAAc,QAAQ,IAAI,WAAW;AAE3D,KAAI,kBAAkB,KACpB,QAAO;AAGT,KACE,cAAc,WAAW,WAAW,IACpC,cAAc,WAAW,UAAU,CAEnC,QAAO;AAGT,QAAO,WAAW"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { runGitCommand } from "./git.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { ReleasesConfigResponse } from "@interfere/sdk/models/releases-config-response.js";
|
|
3
|
+
import { CreateReleaseRequest } from "@interfere/types/releases/definition";
|
|
3
4
|
|
|
4
5
|
//#region src/internal/build/release/index.d.ts
|
|
5
|
-
declare function
|
|
6
|
+
declare function resolveReleaseRequest(buildId: string, config: ReleasesConfigResponse): CreateReleaseRequest;
|
|
6
7
|
//#endregion
|
|
7
|
-
export {
|
|
8
|
+
export { resolveReleaseRequest, runGitCommand };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/internal/build/release/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/internal/build/release/index.ts"],"mappings":";;;;;iBA2BgB,qBAAA,CACd,OAAA,UACA,MAAA,EAAQ,sBAAA,GACP,oBAAA"}
|
|
@@ -1,24 +1,18 @@
|
|
|
1
|
+
import { log } from "../../logger.mjs";
|
|
1
2
|
import { runGitCommand } from "./git.mjs";
|
|
2
3
|
import { vercel_exports } from "./destinations/vercel.mjs";
|
|
3
4
|
import { github_exports } from "./sources/github.mjs";
|
|
4
|
-
import { Interfere } from "@interfere/sdk";
|
|
5
|
-
import { InterfereHTTPError } from "@interfere/sdk/models/errors/interfere-http-error.js";
|
|
6
5
|
//#region src/internal/build/release/index.ts
|
|
7
6
|
const sources = { github: github_exports };
|
|
8
7
|
const destinations = { vercel: vercel_exports };
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
function resolveReleaseRequest(buildId, config) {
|
|
9
|
+
if (!config.surface.sourceProvider) return log.fatal("Missing version control provider", ["This surface does not have a version control provider configured.", `Configure one at https://interfere.com/~/${config.org.slug}/surfaces/${config.surface.slug}`]);
|
|
10
|
+
if (!config.surface.destinationProvider) return log.fatal("Missing deployment target", ["This surface does not have a deployment target integration configured.", `Configure one at https://interfere.com/~/${config.org.slug}/surfaces/${config.surface.slug}`]);
|
|
11
|
+
return {
|
|
12
|
+
source: sources[config.surface.sourceProvider].resolve(),
|
|
13
|
+
destination: destinations[config.surface.destinationProvider].resolve(),
|
|
14
14
|
buildId
|
|
15
15
|
};
|
|
16
|
-
try {
|
|
17
|
-
return await sdk.releases.createRelease(request, { headers: { "x-api-key": apiKey } });
|
|
18
|
-
} catch (error) {
|
|
19
|
-
if (error instanceof InterfereHTTPError && error.statusCode === 404) throw new Error(`Interfere release API returned 404 at '${error.rawResponse.url}'. Is INTERFERE_API_URL incorrectly set?`);
|
|
20
|
-
throw error;
|
|
21
|
-
}
|
|
22
16
|
}
|
|
23
17
|
//#endregion
|
|
24
|
-
export {
|
|
18
|
+
export { resolveReleaseRequest, runGitCommand };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/internal/build/release/index.ts"],"sourcesContent":["import type {\n DestinationProvider,\n ReleaseDestinationMetadata,\n ReleaseSourceMetadata,\n SourceProvider,\n} from \"@interfere/types/integrations\";\nimport
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/internal/build/release/index.ts"],"sourcesContent":["import type {\n DestinationProvider,\n ReleaseDestinationMetadata,\n ReleaseSourceMetadata,\n SourceProvider,\n} from \"@interfere/types/integrations\";\n\nimport * as vercel from \"./destinations/vercel.js\";\nimport * as github from \"./sources/github.js\";\nimport type { CreateReleaseRequest } from \"@interfere/types/releases/definition\";\nimport type { ReleasesConfigResponse } from \"@interfere/sdk/models/releases-config-response.js\";\nimport { log } from \"../../logger.js\";\n\nexport { runGitCommand } from \"./git.js\";\n\ninterface Resolver<T> {\n resolve(): T;\n}\n\nconst sources: Record<SourceProvider, Resolver<ReleaseSourceMetadata>> = {\n github,\n};\n\nconst destinations: Record<DestinationProvider, Resolver<ReleaseDestinationMetadata>> = {\n vercel,\n};\n\nexport function resolveReleaseRequest(\n buildId: string,\n config: ReleasesConfigResponse\n): CreateReleaseRequest {\n if (!config.surface.sourceProvider) {\n return log.fatal(\"Missing version control provider\", [\n \"This surface does not have a version control provider configured.\",\n `Configure one at https://interfere.com/~/${config.org.slug}/surfaces/${config.surface.slug}`,\n ]);\n }\n\n if (!config.surface.destinationProvider) {\n return log.fatal(\"Missing deployment target\", [\n \"This surface does not have a deployment target integration configured.\",\n `Configure one at https://interfere.com/~/${config.org.slug}/surfaces/${config.surface.slug}`,\n ]);\n }\n\n return {\n source: sources[config.surface.sourceProvider].resolve(),\n destination: destinations[config.surface.destinationProvider].resolve(),\n buildId,\n };\n}\n"],"mappings":";;;;;AAmBA,MAAM,UAAmE,EACvE,QAAA,gBACD;AAED,MAAM,eAAkF,EACtF,QAAA,gBACD;AAED,SAAgB,sBACd,SACA,QACsB;AACtB,KAAI,CAAC,OAAO,QAAQ,eAClB,QAAO,IAAI,MAAM,oCAAoC,CACnD,qEACA,4CAA4C,OAAO,IAAI,KAAK,YAAY,OAAO,QAAQ,OACxF,CAAC;AAGJ,KAAI,CAAC,OAAO,QAAQ,oBAClB,QAAO,IAAI,MAAM,6BAA6B,CAC5C,0EACA,4CAA4C,OAAO,IAAI,KAAK,YAAY,OAAO,QAAQ,OACxF,CAAC;AAGJ,QAAO;EACL,QAAQ,QAAQ,OAAO,QAAQ,gBAAgB,SAAS;EACxD,aAAa,aAAa,OAAO,QAAQ,qBAAqB,SAAS;EACvE;EACD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
2
|
-
import { createHash } from "node:crypto";
|
|
3
2
|
import { readFile, readdir } from "node:fs/promises";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
4
|
//#region src/internal/build/source-maps/discover.ts
|
|
5
5
|
const SOURCEMAPPING_RE = /\/\/[#@]\s*sourceMappingURL=(\S+)\s*$/;
|
|
6
6
|
function resolveDistDir(projectDir, distDir) {
|
|
@@ -1,23 +1,26 @@
|
|
|
1
|
+
import { SourceMapFile, discover, normalizeDistDir } from "./discover.mjs";
|
|
2
|
+
|
|
1
3
|
//#region src/internal/build/source-maps/index.d.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
declare function buildUploadBody(discovered: {
|
|
5
|
+
files: SourceMapFile[];
|
|
6
|
+
mapping: Record<string, string>;
|
|
7
|
+
sourceFileCount: number;
|
|
8
|
+
}): {
|
|
9
|
+
body: {
|
|
10
|
+
files: {
|
|
11
|
+
fileName: string;
|
|
12
|
+
content: Blob;
|
|
13
|
+
}[];
|
|
14
|
+
metadata: {
|
|
15
|
+
sourceMapToGenerated: Record<string, string>;
|
|
16
|
+
hashes: {
|
|
17
|
+
[k: string]: string;
|
|
18
|
+
};
|
|
19
|
+
sourceFileCount: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
totalBytes: number;
|
|
20
23
|
};
|
|
21
|
-
declare function
|
|
24
|
+
declare function cleanupSourceMaps(files: SourceMapFile[]): Promise<void>;
|
|
22
25
|
//#endregion
|
|
23
|
-
export {
|
|
26
|
+
export { type SourceMapFile, buildUploadBody, cleanupSourceMaps, discover, normalizeDistDir };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/internal/build/source-maps/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/internal/build/source-maps/index.ts"],"mappings":";;;iBAMgB,eAAA,CAAgB,UAAA;EAC9B,KAAA,EAAO,aAAA;EACP,OAAA,EAAS,MAAA;EACT,eAAA;AAAA;;;;;;;;;;;;;;;;iBAqBoB,iBAAA,CAAkB,KAAA,EAAO,aAAA,KAAe,OAAA"}
|
|
@@ -1,34 +1,28 @@
|
|
|
1
1
|
import { discover, normalizeDistDir } from "./discover.mjs";
|
|
2
2
|
import { unlink } from "node:fs/promises";
|
|
3
3
|
//#region src/internal/build/source-maps/index.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (files.length === 0) return {
|
|
7
|
-
ready: false,
|
|
8
|
-
reason: "no_source_maps",
|
|
9
|
-
fileCount: 0
|
|
10
|
-
};
|
|
11
|
-
const { slug, orgSlug, buildId } = await client.createRelease();
|
|
12
|
-
const body = new FormData();
|
|
13
|
-
const hashes = {};
|
|
14
|
-
for (const file of files) {
|
|
15
|
-
body.append("files", new Blob([file.content], { type: "application/json" }), file.path);
|
|
16
|
-
hashes[file.path] = file.hash;
|
|
17
|
-
}
|
|
18
|
-
body.append("metadata", JSON.stringify({
|
|
19
|
-
sourceMapToGenerated: mapping,
|
|
20
|
-
hashes,
|
|
21
|
-
sourceFileCount
|
|
22
|
-
}));
|
|
23
|
-
await client.uploadSourceMaps(slug, body);
|
|
24
|
-
if (cleanup) await Promise.all(files.map((f) => unlink(f.absolute).catch(() => void 0)));
|
|
4
|
+
function buildUploadBody(discovered) {
|
|
5
|
+
let totalBytes = 0;
|
|
25
6
|
return {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
7
|
+
body: {
|
|
8
|
+
files: discovered.files.map((file) => {
|
|
9
|
+
totalBytes += file.content.length;
|
|
10
|
+
return {
|
|
11
|
+
fileName: file.path,
|
|
12
|
+
content: new Blob([file.content], { type: "application/json" })
|
|
13
|
+
};
|
|
14
|
+
}),
|
|
15
|
+
metadata: {
|
|
16
|
+
sourceMapToGenerated: discovered.mapping,
|
|
17
|
+
hashes: Object.fromEntries(discovered.files.map((f) => [f.path, f.hash])),
|
|
18
|
+
sourceFileCount: discovered.sourceFileCount
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
totalBytes
|
|
31
22
|
};
|
|
32
23
|
}
|
|
24
|
+
async function cleanupSourceMaps(files) {
|
|
25
|
+
await Promise.all(files.map((f) => unlink(f.absolute).catch(() => void 0)));
|
|
26
|
+
}
|
|
33
27
|
//#endregion
|
|
34
|
-
export {
|
|
28
|
+
export { buildUploadBody, cleanupSourceMaps, discover, normalizeDistDir };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/internal/build/source-maps/index.ts"],"sourcesContent":["import { unlink } from \"node:fs/promises\";\n\nimport {
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/internal/build/source-maps/index.ts"],"sourcesContent":["import { unlink } from \"node:fs/promises\";\n\nimport type { SourceMapFile } from \"./discover.js\";\n\nexport { discover, normalizeDistDir, type SourceMapFile } from \"./discover.js\";\n\nexport function buildUploadBody(discovered: {\n files: SourceMapFile[];\n mapping: Record<string, string>;\n sourceFileCount: number;\n}) {\n let totalBytes = 0;\n\n const files = discovered.files.map((file) => {\n totalBytes += file.content.length;\n return {\n fileName: file.path,\n content: new Blob([file.content], { type: \"application/json\" }),\n };\n });\n\n const metadata = {\n sourceMapToGenerated: discovered.mapping,\n hashes: Object.fromEntries(discovered.files.map((f) => [f.path, f.hash])),\n sourceFileCount: discovered.sourceFileCount,\n };\n\n return { body: { files, metadata }, totalBytes };\n}\n\nexport async function cleanupSourceMaps(files: SourceMapFile[]) {\n await Promise.all(files.map((f) => unlink(f.absolute).catch(() => undefined)));\n}\n"],"mappings":";;;AAMA,SAAgB,gBAAgB,YAI7B;CACD,IAAI,aAAa;AAgBjB,QAAO;EAAE,MAAM;GAAE,OAdH,WAAW,MAAM,KAAK,SAAS;AAC3C,kBAAc,KAAK,QAAQ;AAC3B,WAAO;KACL,UAAU,KAAK;KACf,SAAS,IAAI,KAAK,CAAC,KAAK,QAAQ,EAAE,EAAE,MAAM,oBAAoB,CAAC;KAChE;KACD;GAQsB,UANP;IACf,sBAAsB,WAAW;IACjC,QAAQ,OAAO,YAAY,WAAW,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACzE,iBAAiB,WAAW;IAC7B;GAEiC;EAAE;EAAY;;AAGlD,eAAsB,kBAAkB,OAAwB;AAC9D,OAAM,QAAQ,IAAI,MAAM,KAAK,MAAM,OAAO,EAAE,SAAS,CAAC,YAAY,KAAA,EAAU,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.mjs","names":[],"sources":["../../src/internal/env.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport { parseEnvValue } from \"@interfere/types/sdk/env\";\nimport type { Env } from \"@interfere/types/sdk/runtime\";\nimport { normalizeEnv } from \"@interfere/types/sdk/runtime\";\n\nexport interface InterfereEnv {\n readonly apiKey: string | null;\n readonly apiUrl: string;\n readonly nextRuntime: string | null;\n readonly nodeEnvironment: Exclude<Env, null>;\n readonly release: {\n readonly sourceId: string | null;\n readonly destinationId: string | null;\n };\n}\n\nexport function readInterfereEnv(): InterfereEnv {\n const nodeEnvironment = normalizeEnv(process.env.NODE_ENV) ?? \"production\";\n return {\n apiKey: parseEnvValue(process.env.INTERFERE_API_KEY),\n apiUrl: parseEnvValue(process.env.INTERFERE_API_URL) ?? API_URL,\n nextRuntime: parseEnvValue(process.env.NEXT_RUNTIME),\n nodeEnvironment,\n release: {\n sourceId: parseEnvValue(process.env.NEXT_PUBLIC_INTERFERE_BUILD_ID),\n destinationId: parseEnvValue(\n process.env.NEXT_PUBLIC_INTERFERE_RELEASE_ID\n ),\n },\n };\n}\n"],"mappings":";;;;AAgBA,SAAgB,mBAAiC;CAC/C,MAAM,kBAAkB,aAAa,QAAQ,IAAI,SAAS,IAAI;
|
|
1
|
+
{"version":3,"file":"env.mjs","names":[],"sources":["../../src/internal/env.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport { parseEnvValue } from \"@interfere/types/sdk/env\";\nimport type { Env } from \"@interfere/types/sdk/runtime\";\nimport { normalizeEnv } from \"@interfere/types/sdk/runtime\";\n\nexport interface InterfereEnv {\n readonly apiKey: string | null;\n readonly apiUrl: string;\n readonly nextRuntime: string | null;\n readonly nodeEnvironment: Exclude<Env, null>;\n readonly release: {\n readonly sourceId: string | null;\n readonly destinationId: string | null;\n };\n}\n\nexport function readInterfereEnv(): InterfereEnv {\n const nodeEnvironment = normalizeEnv(process.env.NODE_ENV) ?? \"production\";\n\n return {\n apiKey: parseEnvValue(process.env.INTERFERE_API_KEY),\n apiUrl: parseEnvValue(process.env.INTERFERE_API_URL) ?? API_URL,\n nextRuntime: parseEnvValue(process.env.NEXT_RUNTIME),\n nodeEnvironment,\n release: {\n sourceId: parseEnvValue(process.env.NEXT_PUBLIC_INTERFERE_BUILD_ID),\n destinationId: parseEnvValue(\n process.env.NEXT_PUBLIC_INTERFERE_RELEASE_ID\n ),\n },\n };\n}\n"],"mappings":";;;;AAgBA,SAAgB,mBAAiC;CAC/C,MAAM,kBAAkB,aAAa,QAAQ,IAAI,SAAS,IAAI;AAE9D,QAAO;EACL,QAAQ,cAAc,QAAQ,IAAI,kBAAkB;EACpD,QAAQ,cAAc,QAAQ,IAAI,kBAAkB,IAAI;EACxD,aAAa,cAAc,QAAQ,IAAI,aAAa;EACpD;EACA,SAAS;GACP,UAAU,cAAc,QAAQ,IAAI,+BAA+B;GACnE,eAAe,cACb,QAAQ,IAAI,iCACb;GACF;EACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.mts","names":[],"sources":["../../src/internal/logger.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"logger.d.mts","names":[],"sources":["../../src/internal/logger.ts"],"mappings":";cA6Ea,GAAA;wBACS,KAAA;wBACA,KAAA;yBACC,KAAA;uBACF,KAAA;AAAA"}
|
package/dist/internal/logger.mjs
CHANGED
|
@@ -4,23 +4,33 @@ const styles = {
|
|
|
4
4
|
info: {
|
|
5
5
|
prefix: `${chalk.whiteBright.bold("❖")}`,
|
|
6
6
|
text: chalk.cyan.bold,
|
|
7
|
-
content: chalk.white
|
|
7
|
+
content: chalk.white,
|
|
8
|
+
prependLevel: false
|
|
8
9
|
},
|
|
9
10
|
warn: {
|
|
10
11
|
prefix: `${chalk.yellow.bold("⚠")} `,
|
|
11
12
|
text: chalk.yellow.bold,
|
|
12
|
-
content: chalk.yellowBright
|
|
13
|
+
content: chalk.yellowBright,
|
|
14
|
+
prependLevel: false
|
|
13
15
|
},
|
|
14
16
|
error: {
|
|
15
17
|
prefix: `${chalk.red.bold("⨯")} `,
|
|
16
18
|
text: chalk.red.bold,
|
|
17
|
-
content: chalk.redBright
|
|
19
|
+
content: chalk.redBright,
|
|
20
|
+
prependLevel: true
|
|
21
|
+
},
|
|
22
|
+
fatal: {
|
|
23
|
+
prefix: `${chalk.red.bold("⨯")} `,
|
|
24
|
+
text: chalk.red.bold,
|
|
25
|
+
content: chalk.redBright,
|
|
26
|
+
prependLevel: true
|
|
18
27
|
}
|
|
19
28
|
};
|
|
20
29
|
const consoleMethods = {
|
|
21
30
|
info: "log",
|
|
22
31
|
warn: "warn",
|
|
23
|
-
error: "error"
|
|
32
|
+
error: "error",
|
|
33
|
+
fatal: "error"
|
|
24
34
|
};
|
|
25
35
|
function isTestEnv() {
|
|
26
36
|
return Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);
|
|
@@ -32,13 +42,19 @@ function emit(level, title, lines) {
|
|
|
32
42
|
const fn = globalThis.console[method];
|
|
33
43
|
if (typeof fn !== "function") return;
|
|
34
44
|
const invoke = (...args) => Reflect.apply(fn, globalThis.console, args);
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
const prependLevel = style.prependLevel ? `[${style.text(level.toUpperCase())}] ` : "";
|
|
46
|
+
invoke(`${prependLevel} ${chalk.white("Interfere →")} ${style.text(title)}`);
|
|
47
|
+
for (const [i, line] of lines.entries()) invoke(`${prependLevel} ${i === lines.length - 1 ? "└" : "├"} ${style.content(line)}`);
|
|
37
48
|
}
|
|
38
49
|
const log = {
|
|
39
50
|
info: (title, lines) => emit("info", title, lines),
|
|
40
51
|
warn: (title, lines) => emit("warn", title, lines),
|
|
41
|
-
error: (title, lines) => emit("error", title, lines)
|
|
52
|
+
error: (title, lines) => emit("error", title, lines),
|
|
53
|
+
fatal(title, lines) {
|
|
54
|
+
emit("fatal", title, lines);
|
|
55
|
+
if (isTestEnv()) throw new Error(title);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
42
58
|
};
|
|
43
59
|
//#endregion
|
|
44
60
|
export { log };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.mjs","names":[],"sources":["../../src/internal/logger.ts"],"sourcesContent":["import chalk from \"chalk\";\n\ntype LogLevel = \"info\" | \"warn\" | \"error\";\n\nconst styles = {\n info: {\n prefix: `${chalk.whiteBright.bold(\"❖\")}`,\n text: chalk.cyan.bold,\n content: chalk.white,\n },\n warn: {\n prefix: `${chalk.yellow.bold(\"⚠\")} `,\n text: chalk.yellow.bold,\n content: chalk.yellowBright,\n },\n error: {\n prefix: `${chalk.red.bold(\"⨯\")} `,\n text: chalk.red.bold,\n content: chalk.redBright,\n },\n} satisfies Record<\n LogLevel,\n {
|
|
1
|
+
{"version":3,"file":"logger.mjs","names":[],"sources":["../../src/internal/logger.ts"],"sourcesContent":["import chalk from \"chalk\";\n\ntype LogLevel = \"info\" | \"warn\" | \"error\" | \"fatal\";\n\nconst styles = {\n info: {\n prefix: `${chalk.whiteBright.bold(\"❖\")}`,\n text: chalk.cyan.bold,\n content: chalk.white,\n prependLevel: false,\n },\n warn: {\n prefix: `${chalk.yellow.bold(\"⚠\")} `,\n text: chalk.yellow.bold,\n content: chalk.yellowBright,\n prependLevel: false,\n },\n error: {\n prefix: `${chalk.red.bold(\"⨯\")} `,\n text: chalk.red.bold,\n content: chalk.redBright,\n prependLevel: true,\n },\n fatal: {\n prefix: `${chalk.red.bold(\"⨯\")} `,\n text: chalk.red.bold,\n content: chalk.redBright,\n prependLevel: true,\n },\n} satisfies Record<\n LogLevel,\n {\n prefix: string;\n text: typeof chalk.bold;\n content: typeof chalk;\n prependLevel: boolean;\n }\n>;\n\nconst consoleMethods = {\n info: \"log\",\n warn: \"warn\",\n error: \"error\",\n fatal: \"error\",\n} satisfies Record<LogLevel, string>;\n\nfunction isTestEnv() {\n return Boolean(process.env.VITEST || process.env.VITEST_WORKER_ID);\n}\n\nfunction emit(level: LogLevel, title: string, lines: string[]) {\n if (isTestEnv()) {\n return;\n }\n\n const style = styles[level];\n const method = consoleMethods[level] as keyof Console;\n const fn = globalThis.console[method];\n if (typeof fn !== \"function\") {\n return;\n }\n\n const invoke = (...args: unknown[]) =>\n Reflect.apply(fn, globalThis.console, args);\n\n const prependLevel = style.prependLevel\n ? `[${style.text(level.toUpperCase())}] `\n : \"\";\n\n invoke(`${prependLevel} ${chalk.white(\"Interfere →\")} ${style.text(title)}`);\n\n for (const [i, line] of lines.entries()) {\n const connector = i === lines.length - 1 ? \"└\" : \"├\";\n invoke(`${prependLevel} ${connector} ${style.content(line)}`);\n }\n}\n\nexport const log = {\n info: (title: string, lines: string[]) => emit(\"info\", title, lines),\n warn: (title: string, lines: string[]) => emit(\"warn\", title, lines),\n error: (title: string, lines: string[]) => emit(\"error\", title, lines),\n fatal(title: string, lines: string[]): never {\n emit(\"fatal\", title, lines);\n\n if (isTestEnv()) {\n throw new Error(title);\n }\n\n process.exit(1);\n },\n};\n"],"mappings":";;AAIA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ,GAAG,MAAM,YAAY,KAAK,IAAI;EACtC,MAAM,MAAM,KAAK;EACjB,SAAS,MAAM;EACf,cAAc;EACf;CACD,MAAM;EACJ,QAAQ,GAAG,MAAM,OAAO,KAAK,IAAI,CAAC;EAClC,MAAM,MAAM,OAAO;EACnB,SAAS,MAAM;EACf,cAAc;EACf;CACD,OAAO;EACL,QAAQ,GAAG,MAAM,IAAI,KAAK,IAAI,CAAC;EAC/B,MAAM,MAAM,IAAI;EAChB,SAAS,MAAM;EACf,cAAc;EACf;CACD,OAAO;EACL,QAAQ,GAAG,MAAM,IAAI,KAAK,IAAI,CAAC;EAC/B,MAAM,MAAM,IAAI;EAChB,SAAS,MAAM;EACf,cAAc;EACf;CACF;AAUD,MAAM,iBAAiB;CACrB,MAAM;CACN,MAAM;CACN,OAAO;CACP,OAAO;CACR;AAED,SAAS,YAAY;AACnB,QAAO,QAAQ,QAAQ,IAAI,UAAU,QAAQ,IAAI,iBAAiB;;AAGpE,SAAS,KAAK,OAAiB,OAAe,OAAiB;AAC7D,KAAI,WAAW,CACb;CAGF,MAAM,QAAQ,OAAO;CACrB,MAAM,SAAS,eAAe;CAC9B,MAAM,KAAK,WAAW,QAAQ;AAC9B,KAAI,OAAO,OAAO,WAChB;CAGF,MAAM,UAAU,GAAG,SACjB,QAAQ,MAAM,IAAI,WAAW,SAAS,KAAK;CAE7C,MAAM,eAAe,MAAM,eACvB,IAAI,MAAM,KAAK,MAAM,aAAa,CAAC,CAAC,MACpC;AAEJ,QAAO,GAAG,aAAa,GAAG,MAAM,MAAM,cAAc,CAAC,GAAG,MAAM,KAAK,MAAM,GAAG;AAE5E,MAAK,MAAM,CAAC,GAAG,SAAS,MAAM,SAAS,CAErC,QAAO,GAAG,aAAa,GADL,MAAM,MAAM,SAAS,IAAI,MAAM,IACb,GAAG,MAAM,QAAQ,KAAK,GAAG;;AAIjE,MAAa,MAAM;CACjB,OAAO,OAAe,UAAoB,KAAK,QAAQ,OAAO,MAAM;CACpE,OAAO,OAAe,UAAoB,KAAK,QAAQ,OAAO,MAAM;CACpE,QAAQ,OAAe,UAAoB,KAAK,SAAS,OAAO,MAAM;CACtE,MAAM,OAAe,OAAwB;AAC3C,OAAK,SAAS,OAAO,MAAM;AAE3B,MAAI,WAAW,CACb,OAAM,IAAI,MAAM,MAAM;AAGxB,UAAQ,KAAK,EAAE;;CAElB"}
|
|
@@ -84,7 +84,8 @@ async function handleIngest(request, env) {
|
|
|
84
84
|
"x-api-key": env.apiKey,
|
|
85
85
|
...traceparent ? { traceparent } : {}
|
|
86
86
|
},
|
|
87
|
-
body: JSON.stringify(injectReleaseMetadata(envelopes, env.release))
|
|
87
|
+
body: JSON.stringify(injectReleaseMetadata(envelopes, env.release)),
|
|
88
|
+
signal: AbortSignal.timeout(1e4)
|
|
88
89
|
});
|
|
89
90
|
return new Response(upstream.body, {
|
|
90
91
|
status: upstream.status,
|
|
@@ -102,7 +103,8 @@ async function forwardToCollector(request, env, subPath) {
|
|
|
102
103
|
"x-api-key": env.apiKey,
|
|
103
104
|
...traceparent ? { traceparent } : {}
|
|
104
105
|
},
|
|
105
|
-
body
|
|
106
|
+
body,
|
|
107
|
+
signal: AbortSignal.timeout(1e4)
|
|
106
108
|
});
|
|
107
109
|
if (!upstream.ok) {
|
|
108
110
|
const body = await upstream.text().catch(() => "");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handle-post.mjs","names":[],"sources":["../../../src/internal/route/handle-post.ts"],"sourcesContent":["import { API_PATHS } from \"@interfere/constants/api\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport { type InterfereEnv, readInterfereEnv } from \"../env.js\";\nimport { log } from \"../logger.js\";\n\nfunction parseEnvelopes(value: unknown): Envelope[] | null {\n if (!Array.isArray(value)) {\n return null;\n }\n\n return value as Envelope[];\n}\n\nfunction injectReleaseMetadata(\n envelopes: Envelope[],\n metadata: { sourceId: string | null; destinationId: string | null }\n): Envelope[] {\n if (metadata.sourceId === null && metadata.destinationId === null) {\n return envelopes;\n }\n\n return envelopes.map((envelope) => ({\n ...envelope,\n buildId: metadata.sourceId ?? envelope.buildId,\n releaseId: metadata.destinationId ?? envelope.releaseId,\n }));\n}\n\nfunction formatProxyError(error: unknown): {\n message: string;\n lines: string[];\n} {\n if (!(error instanceof Error)) {\n return {\n message: String(error),\n lines: [String(error)],\n };\n }\n\n const lines = [`${error.name}: ${error.message}`];\n\n if (\"cause\" in error && error.cause) {\n const cause =\n error.cause instanceof Error ? error.cause.message : String(error.cause);\n lines.push(`cause: ${cause}`);\n }\n\n if (\n \"code\" in error &&\n typeof (error as NodeJS.ErrnoException).code === \"string\"\n ) {\n lines.push(`code: ${(error as NodeJS.ErrnoException).code}`);\n }\n\n return {\n message: `${error.name}: ${error.message}`,\n lines,\n };\n}\n\nconst PROXY_PATH_PATTERN = /\\/api\\/interfere(\\/.*)/;\n\nfunction extractSubPath(request: Request): string {\n const url = new URL(request.url);\n const match = url.pathname.match(PROXY_PATH_PATTERN);\n return match?.[1] ?? \"/\";\n}\n\ninterface AuthenticatedEnv {\n apiKey: string;\n apiUrl: string;\n release: InterfereEnv[\"release\"];\n}\n\nexport async function handlePost(request: Request): Promise<Response> {\n const env = readInterfereEnv();\n\n if (env.apiKey === null) {\n log.warn(\"Not configured\", [\n \"INTERFERE_API_KEY is not set. The proxy route will return 503.\",\n ]);\n\n return Response.json(\n {\n code: \"INTERFERE_NOT_CONFIGURED\",\n message: \"INTERFERE_API_KEY is required.\",\n },\n { status: 503 }\n );\n }\n\n const authed: AuthenticatedEnv = {\n apiKey: env.apiKey,\n apiUrl: env.apiUrl,\n release: env.release,\n };\n\n const subPath = extractSubPath(request);\n\n try {\n if (subPath === API_PATHS.INGEST) {\n return await handleIngest(request, authed);\n }\n\n return await forwardToCollector(request, authed, subPath);\n } catch (error) {\n const detail = formatProxyError(error);\n log.error(`Proxy ${request.method} ${subPath} failed`, detail.lines);\n return Response.json(\n {\n code: \"INTERFERE_PROXY_ERROR\",\n message: detail.message,\n },\n { status: 502 }\n );\n }\n}\n\nasync function handleIngest(\n request: Request,\n env: AuthenticatedEnv\n): Promise<Response> {\n let payload: unknown;\n try {\n payload = await request.json();\n } catch {\n return Response.json(\n {\n code: \"INTERFERE_INVALID_JSON\",\n message: \"Request body must be valid JSON.\",\n },\n { status: 400 }\n );\n }\n\n const envelopes = parseEnvelopes(payload);\n if (envelopes === null) {\n return Response.json(\n {\n code: \"INTERFERE_INVALID_ENVELOPES\",\n message: \"Request body must be an array of envelopes.\",\n },\n { status: 400 }\n );\n }\n\n const traceparent = request.headers.get(\"traceparent\");\n const upstream = await fetch(`${env.apiUrl}${API_PATHS.INGEST}`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": env.apiKey,\n ...(traceparent ? { traceparent } : {}),\n },\n body: JSON.stringify(injectReleaseMetadata(envelopes, env.release)),\n });\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n });\n}\n\nasync function forwardToCollector(\n request: Request,\n env: AuthenticatedEnv,\n subPath: string\n): Promise<Response> {\n const url = `${env.apiUrl}${subPath}`;\n const traceparent = request.headers.get(\"traceparent\");\n const body = await request.text();\n\n const upstream = await fetch(url, {\n method: request.method,\n headers: {\n \"content-type\": request.headers.get(\"content-type\") ?? \"application/json\",\n \"x-api-key\": env.apiKey,\n ...(traceparent ? { traceparent } : {}),\n },\n body,\n });\n\n if (!upstream.ok) {\n const body = await upstream.text().catch(() => \"\");\n log.error(`Upstream ${upstream.status} for ${request.method} ${subPath}`, [\n body,\n ]);\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_ERROR\", message: body },\n { status: upstream.status }\n );\n }\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n });\n}\n"],"mappings":";;;;AAMA,SAAS,eAAe,OAAmC;AACzD,KAAI,CAAC,MAAM,QAAQ,MAAM,CACvB,QAAO;AAGT,QAAO;;AAGT,SAAS,sBACP,WACA,UACY;AACZ,KAAI,SAAS,aAAa,QAAQ,SAAS,kBAAkB,KAC3D,QAAO;AAGT,QAAO,UAAU,KAAK,cAAc;EAClC,GAAG;EACH,SAAS,SAAS,YAAY,SAAS;EACvC,WAAW,SAAS,iBAAiB,SAAS;EAC/C,EAAE;;AAGL,SAAS,iBAAiB,OAGxB;AACA,KAAI,EAAE,iBAAiB,OACrB,QAAO;EACL,SAAS,OAAO,MAAM;EACtB,OAAO,CAAC,OAAO,MAAM,CAAC;EACvB;CAGH,MAAM,QAAQ,CAAC,GAAG,MAAM,KAAK,IAAI,MAAM,UAAU;AAEjD,KAAI,WAAW,SAAS,MAAM,OAAO;EACnC,MAAM,QACJ,MAAM,iBAAiB,QAAQ,MAAM,MAAM,UAAU,OAAO,MAAM,MAAM;AAC1E,QAAM,KAAK,UAAU,QAAQ;;AAG/B,KACE,UAAU,SACV,OAAQ,MAAgC,SAAS,SAEjD,OAAM,KAAK,SAAU,MAAgC,OAAO;AAG9D,QAAO;EACL,SAAS,GAAG,MAAM,KAAK,IAAI,MAAM;EACjC;EACD;;AAGH,MAAM,qBAAqB;AAE3B,SAAS,eAAe,SAA0B;AAGhD,QAFY,IAAI,IAAI,QAAQ,IAAI,CACd,SAAS,MAAM,mBAAmB,GACrC,MAAM;;AASvB,eAAsB,WAAW,SAAqC;CACpE,MAAM,MAAM,kBAAkB;AAE9B,KAAI,IAAI,WAAW,MAAM;AACvB,MAAI,KAAK,kBAAkB,CACzB,iEACD,CAAC;AAEF,SAAO,SAAS,KACd;GACE,MAAM;GACN,SAAS;GACV,EACD,EAAE,QAAQ,KAAK,CAChB;;CAGH,MAAM,SAA2B;EAC/B,QAAQ,IAAI;EACZ,QAAQ,IAAI;EACZ,SAAS,IAAI;EACd;CAED,MAAM,UAAU,eAAe,QAAQ;AAEvC,KAAI;AACF,MAAI,YAAY,UAAU,OACxB,QAAO,MAAM,aAAa,SAAS,OAAO;AAG5C,SAAO,MAAM,mBAAmB,SAAS,QAAQ,QAAQ;UAClD,OAAO;EACd,MAAM,SAAS,iBAAiB,MAAM;AACtC,MAAI,MAAM,SAAS,QAAQ,OAAO,GAAG,QAAQ,UAAU,OAAO,MAAM;AACpE,SAAO,SAAS,KACd;GACE,MAAM;GACN,SAAS,OAAO;GACjB,EACD,EAAE,QAAQ,KAAK,CAChB;;;AAIL,eAAe,aACb,SACA,KACmB;CACnB,IAAI;AACJ,KAAI;AACF,YAAU,MAAM,QAAQ,MAAM;SACxB;AACN,SAAO,SAAS,KACd;GACE,MAAM;GACN,SAAS;GACV,EACD,EAAE,QAAQ,KAAK,CAChB;;CAGH,MAAM,YAAY,eAAe,QAAQ;AACzC,KAAI,cAAc,KAChB,QAAO,SAAS,KACd;EACE,MAAM;EACN,SAAS;EACV,EACD,EAAE,QAAQ,KAAK,CAChB;CAGH,MAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc;CACtD,MAAM,WAAW,MAAM,MAAM,GAAG,IAAI,SAAS,UAAU,UAAU;EAC/D,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,aAAa,IAAI;GACjB,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;GACvC;EACD,MAAM,KAAK,UAAU,sBAAsB,WAAW,IAAI,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"handle-post.mjs","names":[],"sources":["../../../src/internal/route/handle-post.ts"],"sourcesContent":["import { API_PATHS } from \"@interfere/constants/api\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport { type InterfereEnv, readInterfereEnv } from \"../env.js\";\nimport { log } from \"../logger.js\";\n\nfunction parseEnvelopes(value: unknown): Envelope[] | null {\n if (!Array.isArray(value)) {\n return null;\n }\n\n return value as Envelope[];\n}\n\nfunction injectReleaseMetadata(\n envelopes: Envelope[],\n metadata: { sourceId: string | null; destinationId: string | null }\n): Envelope[] {\n if (metadata.sourceId === null && metadata.destinationId === null) {\n return envelopes;\n }\n\n return envelopes.map((envelope) => ({\n ...envelope,\n buildId: metadata.sourceId ?? envelope.buildId,\n releaseId: metadata.destinationId ?? envelope.releaseId,\n }));\n}\n\nfunction formatProxyError(error: unknown): {\n message: string;\n lines: string[];\n} {\n if (!(error instanceof Error)) {\n return {\n message: String(error),\n lines: [String(error)],\n };\n }\n\n const lines = [`${error.name}: ${error.message}`];\n\n if (\"cause\" in error && error.cause) {\n const cause =\n error.cause instanceof Error ? error.cause.message : String(error.cause);\n lines.push(`cause: ${cause}`);\n }\n\n if (\n \"code\" in error &&\n typeof (error as NodeJS.ErrnoException).code === \"string\"\n ) {\n lines.push(`code: ${(error as NodeJS.ErrnoException).code}`);\n }\n\n return {\n message: `${error.name}: ${error.message}`,\n lines,\n };\n}\n\nconst PROXY_PATH_PATTERN = /\\/api\\/interfere(\\/.*)/;\n\nfunction extractSubPath(request: Request): string {\n const url = new URL(request.url);\n const match = url.pathname.match(PROXY_PATH_PATTERN);\n return match?.[1] ?? \"/\";\n}\n\ninterface AuthenticatedEnv {\n apiKey: string;\n apiUrl: string;\n release: InterfereEnv[\"release\"];\n}\n\nexport async function handlePost(request: Request): Promise<Response> {\n const env = readInterfereEnv();\n\n if (env.apiKey === null) {\n log.warn(\"Not configured\", [\n \"INTERFERE_API_KEY is not set. The proxy route will return 503.\",\n ]);\n\n return Response.json(\n {\n code: \"INTERFERE_NOT_CONFIGURED\",\n message: \"INTERFERE_API_KEY is required.\",\n },\n { status: 503 }\n );\n }\n\n const authed: AuthenticatedEnv = {\n apiKey: env.apiKey,\n apiUrl: env.apiUrl,\n release: env.release,\n };\n\n const subPath = extractSubPath(request);\n\n try {\n if (subPath === API_PATHS.INGEST) {\n return await handleIngest(request, authed);\n }\n\n return await forwardToCollector(request, authed, subPath);\n } catch (error) {\n const detail = formatProxyError(error);\n log.error(`Proxy ${request.method} ${subPath} failed`, detail.lines);\n return Response.json(\n {\n code: \"INTERFERE_PROXY_ERROR\",\n message: detail.message,\n },\n { status: 502 }\n );\n }\n}\n\nasync function handleIngest(\n request: Request,\n env: AuthenticatedEnv\n): Promise<Response> {\n let payload: unknown;\n try {\n payload = await request.json();\n } catch {\n return Response.json(\n {\n code: \"INTERFERE_INVALID_JSON\",\n message: \"Request body must be valid JSON.\",\n },\n { status: 400 }\n );\n }\n\n const envelopes = parseEnvelopes(payload);\n if (envelopes === null) {\n return Response.json(\n {\n code: \"INTERFERE_INVALID_ENVELOPES\",\n message: \"Request body must be an array of envelopes.\",\n },\n { status: 400 }\n );\n }\n\n const traceparent = request.headers.get(\"traceparent\");\n const upstream = await fetch(`${env.apiUrl}${API_PATHS.INGEST}`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": env.apiKey,\n ...(traceparent ? { traceparent } : {}),\n },\n body: JSON.stringify(injectReleaseMetadata(envelopes, env.release)),\n signal: AbortSignal.timeout(10_000),\n });\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n });\n}\n\nasync function forwardToCollector(\n request: Request,\n env: AuthenticatedEnv,\n subPath: string\n): Promise<Response> {\n const url = `${env.apiUrl}${subPath}`;\n const traceparent = request.headers.get(\"traceparent\");\n const body = await request.text();\n\n const upstream = await fetch(url, {\n method: request.method,\n headers: {\n \"content-type\": request.headers.get(\"content-type\") ?? \"application/json\",\n \"x-api-key\": env.apiKey,\n ...(traceparent ? { traceparent } : {}),\n },\n body,\n signal: AbortSignal.timeout(10_000),\n });\n\n if (!upstream.ok) {\n const body = await upstream.text().catch(() => \"\");\n log.error(`Upstream ${upstream.status} for ${request.method} ${subPath}`, [\n body,\n ]);\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_ERROR\", message: body },\n { status: upstream.status }\n );\n }\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n });\n}\n"],"mappings":";;;;AAMA,SAAS,eAAe,OAAmC;AACzD,KAAI,CAAC,MAAM,QAAQ,MAAM,CACvB,QAAO;AAGT,QAAO;;AAGT,SAAS,sBACP,WACA,UACY;AACZ,KAAI,SAAS,aAAa,QAAQ,SAAS,kBAAkB,KAC3D,QAAO;AAGT,QAAO,UAAU,KAAK,cAAc;EAClC,GAAG;EACH,SAAS,SAAS,YAAY,SAAS;EACvC,WAAW,SAAS,iBAAiB,SAAS;EAC/C,EAAE;;AAGL,SAAS,iBAAiB,OAGxB;AACA,KAAI,EAAE,iBAAiB,OACrB,QAAO;EACL,SAAS,OAAO,MAAM;EACtB,OAAO,CAAC,OAAO,MAAM,CAAC;EACvB;CAGH,MAAM,QAAQ,CAAC,GAAG,MAAM,KAAK,IAAI,MAAM,UAAU;AAEjD,KAAI,WAAW,SAAS,MAAM,OAAO;EACnC,MAAM,QACJ,MAAM,iBAAiB,QAAQ,MAAM,MAAM,UAAU,OAAO,MAAM,MAAM;AAC1E,QAAM,KAAK,UAAU,QAAQ;;AAG/B,KACE,UAAU,SACV,OAAQ,MAAgC,SAAS,SAEjD,OAAM,KAAK,SAAU,MAAgC,OAAO;AAG9D,QAAO;EACL,SAAS,GAAG,MAAM,KAAK,IAAI,MAAM;EACjC;EACD;;AAGH,MAAM,qBAAqB;AAE3B,SAAS,eAAe,SAA0B;AAGhD,QAFY,IAAI,IAAI,QAAQ,IAAI,CACd,SAAS,MAAM,mBAAmB,GACrC,MAAM;;AASvB,eAAsB,WAAW,SAAqC;CACpE,MAAM,MAAM,kBAAkB;AAE9B,KAAI,IAAI,WAAW,MAAM;AACvB,MAAI,KAAK,kBAAkB,CACzB,iEACD,CAAC;AAEF,SAAO,SAAS,KACd;GACE,MAAM;GACN,SAAS;GACV,EACD,EAAE,QAAQ,KAAK,CAChB;;CAGH,MAAM,SAA2B;EAC/B,QAAQ,IAAI;EACZ,QAAQ,IAAI;EACZ,SAAS,IAAI;EACd;CAED,MAAM,UAAU,eAAe,QAAQ;AAEvC,KAAI;AACF,MAAI,YAAY,UAAU,OACxB,QAAO,MAAM,aAAa,SAAS,OAAO;AAG5C,SAAO,MAAM,mBAAmB,SAAS,QAAQ,QAAQ;UAClD,OAAO;EACd,MAAM,SAAS,iBAAiB,MAAM;AACtC,MAAI,MAAM,SAAS,QAAQ,OAAO,GAAG,QAAQ,UAAU,OAAO,MAAM;AACpE,SAAO,SAAS,KACd;GACE,MAAM;GACN,SAAS,OAAO;GACjB,EACD,EAAE,QAAQ,KAAK,CAChB;;;AAIL,eAAe,aACb,SACA,KACmB;CACnB,IAAI;AACJ,KAAI;AACF,YAAU,MAAM,QAAQ,MAAM;SACxB;AACN,SAAO,SAAS,KACd;GACE,MAAM;GACN,SAAS;GACV,EACD,EAAE,QAAQ,KAAK,CAChB;;CAGH,MAAM,YAAY,eAAe,QAAQ;AACzC,KAAI,cAAc,KAChB,QAAO,SAAS,KACd;EACE,MAAM;EACN,SAAS;EACV,EACD,EAAE,QAAQ,KAAK,CAChB;CAGH,MAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc;CACtD,MAAM,WAAW,MAAM,MAAM,GAAG,IAAI,SAAS,UAAU,UAAU;EAC/D,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,aAAa,IAAI;GACjB,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;GACvC;EACD,MAAM,KAAK,UAAU,sBAAsB,WAAW,IAAI,QAAQ,CAAC;EACnE,QAAQ,YAAY,QAAQ,IAAO;EACpC,CAAC;AAEF,QAAO,IAAI,SAAS,SAAS,MAAM;EACjC,QAAQ,SAAS;EACjB,SAAS,EACP,gBACE,SAAS,QAAQ,IAAI,eAAe,IAAI,oBAC3C;EACF,CAAC;;AAGJ,eAAe,mBACb,SACA,KACA,SACmB;CACnB,MAAM,MAAM,GAAG,IAAI,SAAS;CAC5B,MAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc;CACtD,MAAM,OAAO,MAAM,QAAQ,MAAM;CAEjC,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC,QAAQ,QAAQ;EAChB,SAAS;GACP,gBAAgB,QAAQ,QAAQ,IAAI,eAAe,IAAI;GACvD,aAAa,IAAI;GACjB,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;GACvC;EACD;EACA,QAAQ,YAAY,QAAQ,IAAO;EACpC,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,OAAO,MAAM,SAAS,MAAM,CAAC,YAAY,GAAG;AAClD,MAAI,MAAM,YAAY,SAAS,OAAO,OAAO,QAAQ,OAAO,GAAG,WAAW,CACxE,KACD,CAAC;AACF,SAAO,SAAS,KACd;GAAE,MAAM;GAA4B,SAAS;GAAM,EACnD,EAAE,QAAQ,SAAS,QAAQ,CAC5B;;AAGH,QAAO,IAAI,SAAS,SAAS,MAAM;EACjC,QAAQ,SAAS;EACjB,SAAS,EACP,gBACE,SAAS,QAAQ,IAAI,eAAe,IAAI,oBAC3C;EACF,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
//#region src/internal/route/sw-script.d.ts
|
|
2
|
-
declare const SW_SCRIPT = "importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.3.0/workbox-sw.js');\n\nself.addEventListener('install', function() { self.skipWaiting(); });\nself.addEventListener('activate', function(e) { e.waitUntil(self.clients.claim()); });\n\nself.addEventListener('unhandledrejection', function(event) {\n if (event.reason && event.reason.name === 'no-response') {\n event.preventDefault();\n }\n});\n\nworkbox.setConfig({ debug: false });\n\nworkbox.routing.registerRoute(\n function(ctx) {\n return ctx.request.method === 'POST' && ctx.url.pathname.startsWith('/api/interfere/');\n },\n new workbox.strategies.NetworkOnly({\n plugins: [\n new workbox.backgroundSync.BackgroundSyncPlugin('interfere-queue', {\n maxRetentionTime: 1440,\n }),\n {\n fetchDidSucceed: function(ctx) {\n if (ctx.response.status >= 500) {\n throw new Error(ctx.request.url + ' returned ' + ctx.response.status);\n }\n return ctx.response;\n },\n },\n ],\n }),\n 'POST'\n);";
|
|
2
|
+
declare const SW_SCRIPT = "importScripts('https://storage.googleapis.com/workbox-cdn/releases/7.3.0/workbox-sw.js');\n\nself.addEventListener('install', function() { self.skipWaiting(); });\nself.addEventListener('activate', function(e) { e.waitUntil(self.clients.claim()); });\n\nself.addEventListener('unhandledrejection', function(event) {\n if (event.reason && event.reason.name === 'no-response') {\n event.preventDefault();\n }\n});\n\nworkbox.setConfig({ debug: false });\n\nworkbox.routing.registerRoute(\n function(ctx) {\n return ctx.request.method === 'POST' && ctx.url.pathname.startsWith('/api/interfere/');\n },\n new workbox.strategies.NetworkOnly({\n plugins: [\n new workbox.backgroundSync.BackgroundSyncPlugin('interfere-queue', {\n maxRetentionTime: 1440,\n }),\n {\n fetchDidSucceed: function(ctx) {\n if (ctx.response.status === 429 || ctx.response.status >= 500) {\n throw new Error(ctx.request.url + ' returned ' + ctx.response.status);\n }\n return ctx.response;\n },\n },\n ],\n }),\n 'POST'\n);";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { SW_SCRIPT };
|
|
@@ -24,7 +24,7 @@ workbox.routing.registerRoute(
|
|
|
24
24
|
}),
|
|
25
25
|
{
|
|
26
26
|
fetchDidSucceed: function(ctx) {
|
|
27
|
-
if (ctx.response.status >= 500) {
|
|
27
|
+
if (ctx.response.status === 429 || ctx.response.status >= 500) {
|
|
28
28
|
throw new Error(ctx.request.url + ' returned ' + ctx.response.status);
|
|
29
29
|
}
|
|
30
30
|
return ctx.response;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sw-script.mjs","names":[],"sources":["../../../src/internal/route/sw-script.ts"],"sourcesContent":["export const SW_SCRIPT = `\\\nimportScripts('https://storage.googleapis.com/workbox-cdn/releases/7.3.0/workbox-sw.js');\n\nself.addEventListener('install', function() { self.skipWaiting(); });\nself.addEventListener('activate', function(e) { e.waitUntil(self.clients.claim()); });\n\nself.addEventListener('unhandledrejection', function(event) {\n if (event.reason && event.reason.name === 'no-response') {\n event.preventDefault();\n }\n});\n\nworkbox.setConfig({ debug: false });\n\nworkbox.routing.registerRoute(\n function(ctx) {\n return ctx.request.method === 'POST' && ctx.url.pathname.startsWith('/api/interfere/');\n },\n new workbox.strategies.NetworkOnly({\n plugins: [\n new workbox.backgroundSync.BackgroundSyncPlugin('interfere-queue', {\n maxRetentionTime: 1440,\n }),\n {\n fetchDidSucceed: function(ctx) {\n if (ctx.response.status >= 500) {\n throw new Error(ctx.request.url + ' returned ' + ctx.response.status);\n }\n return ctx.response;\n },\n },\n ],\n }),\n 'POST'\n);`;\n"],"mappings":";AAAA,MAAa,YAAY"}
|
|
1
|
+
{"version":3,"file":"sw-script.mjs","names":[],"sources":["../../../src/internal/route/sw-script.ts"],"sourcesContent":["export const SW_SCRIPT = `\\\nimportScripts('https://storage.googleapis.com/workbox-cdn/releases/7.3.0/workbox-sw.js');\n\nself.addEventListener('install', function() { self.skipWaiting(); });\nself.addEventListener('activate', function(e) { e.waitUntil(self.clients.claim()); });\n\nself.addEventListener('unhandledrejection', function(event) {\n if (event.reason && event.reason.name === 'no-response') {\n event.preventDefault();\n }\n});\n\nworkbox.setConfig({ debug: false });\n\nworkbox.routing.registerRoute(\n function(ctx) {\n return ctx.request.method === 'POST' && ctx.url.pathname.startsWith('/api/interfere/');\n },\n new workbox.strategies.NetworkOnly({\n plugins: [\n new workbox.backgroundSync.BackgroundSyncPlugin('interfere-queue', {\n maxRetentionTime: 1440,\n }),\n {\n fetchDidSucceed: function(ctx) {\n if (ctx.response.status === 429 || ctx.response.status >= 500) {\n throw new Error(ctx.request.url + ' returned ' + ctx.response.status);\n }\n return ctx.response;\n },\n },\n ],\n }),\n 'POST'\n);`;\n"],"mappings":";AAAA,MAAa,YAAY"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@interfere/next",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Build software that never breaks.",
|
|
6
6
|
"keywords": [
|
|
@@ -64,12 +64,11 @@
|
|
|
64
64
|
"test": "bun run test:unit && bun run test:browser"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@interfere/constants": "^
|
|
68
|
-
"@interfere/react": "^
|
|
69
|
-
"@interfere/sdk": "^
|
|
70
|
-
"@interfere/types": "^
|
|
67
|
+
"@interfere/constants": "^4.0.0",
|
|
68
|
+
"@interfere/react": "^4.0.0",
|
|
69
|
+
"@interfere/sdk": "^4.0.0",
|
|
70
|
+
"@interfere/types": "^4.0.0",
|
|
71
71
|
"chalk": "^5.6.2",
|
|
72
|
-
"glob": "^13.0.6",
|
|
73
72
|
"uuid": "^13.0.0"
|
|
74
73
|
},
|
|
75
74
|
"peerDependencies": {
|
|
@@ -79,8 +78,8 @@
|
|
|
79
78
|
"react-dom": ">=19"
|
|
80
79
|
},
|
|
81
80
|
"devDependencies": {
|
|
82
|
-
"@interfere/typescript-config": "^
|
|
83
|
-
"@interfere/vitest-config": "^
|
|
81
|
+
"@interfere/typescript-config": "^4.0.0",
|
|
82
|
+
"@interfere/vitest-config": "^4.0.0",
|
|
84
83
|
"@testing-library/react": "^16.3.2",
|
|
85
84
|
"@types/node": "^24.12.0",
|
|
86
85
|
"@types/react": "19.2.14",
|
|
@@ -89,12 +88,12 @@
|
|
|
89
88
|
"@vitest/browser": "4.1.0",
|
|
90
89
|
"@vitest/browser-playwright": "4.1.0",
|
|
91
90
|
"@vitest/coverage-v8": "^4.0.18",
|
|
92
|
-
"jsdom": "^
|
|
91
|
+
"jsdom": "^29.0.0",
|
|
93
92
|
"next": "^16.1.6",
|
|
94
93
|
"playwright": "^1.56.1",
|
|
95
94
|
"react": "^19.2.4",
|
|
96
95
|
"react-dom": "^19.2.4",
|
|
97
|
-
"tsdown": "^0.21.
|
|
96
|
+
"tsdown": "^0.21.3",
|
|
98
97
|
"typescript": "5.9.3",
|
|
99
98
|
"vitest": "^4.0.18",
|
|
100
99
|
"webpack": "^5.105.1"
|