@patchstack/connect 0.3.22 → 0.3.24
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/AGENT-INSTALL.md +16 -7
- package/README.md +22 -2
- package/dist/chunk-MJOTFUDE.js +87 -0
- package/dist/chunk-MJOTFUDE.js.map +1 -0
- package/dist/cli.js +2868 -129
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +105 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -2
- package/dist/index.d.ts +37 -2
- package/dist/index.js +103 -1
- package/dist/index.js.map +1 -1
- package/dist/protect.cjs +1182 -217
- package/dist/protect.cjs.map +1 -1
- package/dist/protect.d.ts +27 -1
- package/dist/protect.edge.js +3530 -0
- package/dist/protect.edge.js.map +7 -0
- package/dist/protect.js +1066 -193
- package/dist/protect.js.map +1 -1
- package/dist/{refresh-manifest-OW7WT5A6.js → refresh-manifest-MUWVIPFR.js} +12 -2
- package/dist/refresh-manifest-MUWVIPFR.js.map +1 -0
- package/package.json +11 -3
- package/dist/refresh-manifest-OW7WT5A6.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,18 @@ interface Config {
|
|
|
29
29
|
* UUID it returns should be persisted via `persistSiteUuid()`.
|
|
30
30
|
*/
|
|
31
31
|
siteUuid: string | null;
|
|
32
|
+
/**
|
|
33
|
+
* WP-format site API key (`{oauth.secret}-{oauth.id}`) for authenticated
|
|
34
|
+
* block-log reporting via connector `/api/logs/log`. Issued once as `api_key`
|
|
35
|
+
* on first provision. Prefer `PATCHSTACK_API_KEY` in production deploys.
|
|
36
|
+
*/
|
|
37
|
+
apiKey: string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Credential for the authenticated Pulse endpoints (ADR-0018). Exchanged for
|
|
40
|
+
* a short-lived bearer token at `monitor/pulse/token`; never sent directly.
|
|
41
|
+
* Falls back to `apiKey` when unset. Prefer `PATCHSTACK_PULSE_AUTH`.
|
|
42
|
+
*/
|
|
43
|
+
pulseAuth: string | null;
|
|
32
44
|
endpoint: string;
|
|
33
45
|
timeoutMs: number;
|
|
34
46
|
/** Environment to report the manifest under. Defaults to 'production'. */
|
|
@@ -43,6 +55,11 @@ interface Config {
|
|
|
43
55
|
interface StoreManifestResponse {
|
|
44
56
|
/** The UUID of the site the manifest was stored against. Always returned. */
|
|
45
57
|
uuid?: string;
|
|
58
|
+
/**
|
|
59
|
+
* WP-format API key for connector log ingest. Present only when oauth
|
|
60
|
+
* credentials are created in this request (first provision / backfill).
|
|
61
|
+
*/
|
|
62
|
+
api_key?: string;
|
|
46
63
|
stored: boolean;
|
|
47
64
|
manifest_id?: number;
|
|
48
65
|
checksum?: string;
|
|
@@ -101,6 +118,14 @@ declare function postManifest(config: Config, payload: WirePayload): Promise<Sto
|
|
|
101
118
|
|
|
102
119
|
interface ConfigFile {
|
|
103
120
|
siteUuid?: string;
|
|
121
|
+
/** WP-format `{secret}-{oauth.id}` for connector /api/logs/log. Server-only. */
|
|
122
|
+
apiKey?: string;
|
|
123
|
+
/**
|
|
124
|
+
* Credential for the authenticated Pulse endpoints (ADR-0018). Same format as
|
|
125
|
+
* `apiKey` and today the same value, but kept as its own field so the Pulse
|
|
126
|
+
* and block-log paths can diverge without disturbing each other. Server-only.
|
|
127
|
+
*/
|
|
128
|
+
pulseAuth?: string;
|
|
104
129
|
endpoint?: string;
|
|
105
130
|
timeoutMs?: number;
|
|
106
131
|
environment?: string;
|
|
@@ -122,9 +147,19 @@ declare function resolveConfig(options: ResolveConfigOptions): Promise<Config>;
|
|
|
122
147
|
declare function writeConfigFile(cwd: string, config: ConfigFile): Promise<string>;
|
|
123
148
|
/**
|
|
124
149
|
* Merge a new siteUuid into the existing `.patchstackrc.json` (or create it).
|
|
125
|
-
* Preserves any `endpoint` / `timeoutMs` the user already wrote.
|
|
150
|
+
* Preserves any `endpoint` / `timeoutMs` / `apiKey` the user already wrote.
|
|
126
151
|
*/
|
|
127
152
|
declare function persistSiteUuid(cwd: string, siteUuid: string): Promise<string>;
|
|
153
|
+
/**
|
|
154
|
+
* Persist the WP-format api_key issued at provision (for connector log auth).
|
|
155
|
+
* Never embed this value in the public disclosure widget.
|
|
156
|
+
*/
|
|
157
|
+
declare function persistApiKey(cwd: string, apiKey: string): Promise<string>;
|
|
158
|
+
/**
|
|
159
|
+
* Persist the credential used for the authenticated Pulse endpoints.
|
|
160
|
+
* Kept separate from `apiKey` so block-log auth is never disturbed.
|
|
161
|
+
*/
|
|
162
|
+
declare function persistPulseAuth(cwd: string, pulseAuth: string): Promise<string>;
|
|
128
163
|
|
|
129
164
|
/**
|
|
130
165
|
* A best-effort description of the stack a build was produced with, derived
|
|
@@ -218,4 +253,4 @@ interface ScanAndReportResult {
|
|
|
218
253
|
}
|
|
219
254
|
declare function scanAndReport(options?: ScanAndReportOptions): Promise<ScanAndReportResult>;
|
|
220
255
|
|
|
221
|
-
export { type Config, DEFAULT_ENDPOINT, type Ecosystem, type Manifest, type PackageEntry, PatchstackError, type ScanAndReportOptions, type ScanAndReportResult, type SourceWidgetResult, type StackDescriptor, type StoreManifestResponse, WIDGET_MARKER_ATTR, WIDGET_SCRIPT_URL, type WidgetEnsureAction, type WidgetEnsureResult, buildClaimUrl, buildEndpointUrl, buildWidgetTag, buildWirePayload, collectHostingEnvKeys, compareVersions, detectLockfile, detectStack, ensureSourceWidget, ensureWidgetInHtml, findSourceShell, isEmptyStack, persistSiteUuid, postManifest, resolveConfig, scanAndReport, scanLockfile, writeConfigFile };
|
|
256
|
+
export { type Config, DEFAULT_ENDPOINT, type Ecosystem, type Manifest, type PackageEntry, PatchstackError, type ScanAndReportOptions, type ScanAndReportResult, type SourceWidgetResult, type StackDescriptor, type StoreManifestResponse, WIDGET_MARKER_ATTR, WIDGET_SCRIPT_URL, type WidgetEnsureAction, type WidgetEnsureResult, buildClaimUrl, buildEndpointUrl, buildWidgetTag, buildWirePayload, collectHostingEnvKeys, compareVersions, detectLockfile, detectStack, ensureSourceWidget, ensureWidgetInHtml, findSourceShell, isEmptyStack, persistApiKey, persistPulseAuth, persistSiteUuid, postManifest, resolveConfig, scanAndReport, scanLockfile, writeConfigFile };
|
package/dist/index.js
CHANGED
|
@@ -907,6 +907,88 @@ function compareSegments(a, b) {
|
|
|
907
907
|
return 0;
|
|
908
908
|
}
|
|
909
909
|
|
|
910
|
+
// src/pulse-token.ts
|
|
911
|
+
var TOKEN_SKEW_MS = 6e4;
|
|
912
|
+
function buildTokenUrl(manifestEndpoint) {
|
|
913
|
+
const url = new URL(manifestEndpoint);
|
|
914
|
+
const path8 = url.pathname.replace(/\/$/, "");
|
|
915
|
+
url.pathname = path8.endsWith("/manifest") ? `${path8.slice(0, -"/manifest".length)}/token` : "/monitor/pulse/token";
|
|
916
|
+
url.search = "";
|
|
917
|
+
url.hash = "";
|
|
918
|
+
return url.toString();
|
|
919
|
+
}
|
|
920
|
+
function parsePulseAuth(credential) {
|
|
921
|
+
const index = credential.lastIndexOf("-");
|
|
922
|
+
if (index <= 0 || index === credential.length - 1) return null;
|
|
923
|
+
const clientId = credential.slice(index + 1);
|
|
924
|
+
if (!/^\d+$/.test(clientId)) return null;
|
|
925
|
+
return { clientId, clientSecret: credential.slice(0, index) };
|
|
926
|
+
}
|
|
927
|
+
var cached = null;
|
|
928
|
+
var inflight = null;
|
|
929
|
+
function clearPulseToken() {
|
|
930
|
+
cached = null;
|
|
931
|
+
}
|
|
932
|
+
async function getPulseToken(config, fetchImpl = fetch) {
|
|
933
|
+
if (typeof config.pulseAuth !== "string" || config.pulseAuth.length === 0) return null;
|
|
934
|
+
if (cached !== null && Date.now() < cached.expiresAt - TOKEN_SKEW_MS) {
|
|
935
|
+
return cached.token;
|
|
936
|
+
}
|
|
937
|
+
if (inflight !== null) return inflight;
|
|
938
|
+
const credentials = parsePulseAuth(config.pulseAuth);
|
|
939
|
+
if (credentials === null) return null;
|
|
940
|
+
inflight = (async () => {
|
|
941
|
+
try {
|
|
942
|
+
const response = await fetchImpl(buildTokenUrl(config.endpoint), {
|
|
943
|
+
method: "POST",
|
|
944
|
+
headers: {
|
|
945
|
+
"Content-Type": "application/json",
|
|
946
|
+
Accept: "application/json",
|
|
947
|
+
"User-Agent": "@patchstack/connect"
|
|
948
|
+
},
|
|
949
|
+
body: JSON.stringify({
|
|
950
|
+
grant_type: "client_credentials",
|
|
951
|
+
client_id: credentials.clientId,
|
|
952
|
+
client_secret: credentials.clientSecret
|
|
953
|
+
}),
|
|
954
|
+
signal: AbortSignal.timeout(config.timeoutMs)
|
|
955
|
+
});
|
|
956
|
+
if (!response.ok) return null;
|
|
957
|
+
const body = await response.json();
|
|
958
|
+
if (typeof body.access_token !== "string" || body.access_token.length === 0) return null;
|
|
959
|
+
const expiresIn = Number(body.expires_in);
|
|
960
|
+
const ttlMs = Number.isFinite(expiresIn) && expiresIn > 0 ? expiresIn * 1e3 : 36e5;
|
|
961
|
+
cached = { token: body.access_token, expiresAt: Date.now() + ttlMs };
|
|
962
|
+
return body.access_token;
|
|
963
|
+
} catch {
|
|
964
|
+
return null;
|
|
965
|
+
} finally {
|
|
966
|
+
inflight = null;
|
|
967
|
+
}
|
|
968
|
+
})();
|
|
969
|
+
return inflight;
|
|
970
|
+
}
|
|
971
|
+
async function pulseAuthHeader(config, fetchImpl = fetch) {
|
|
972
|
+
const token = await getPulseToken(config, fetchImpl);
|
|
973
|
+
return token === null ? {} : { Authorization: `Bearer ${token}` };
|
|
974
|
+
}
|
|
975
|
+
async function pulseFetch(config, url, init, fetchImpl = fetch) {
|
|
976
|
+
const send = async () => {
|
|
977
|
+
const auth = await pulseAuthHeader(config, fetchImpl);
|
|
978
|
+
const response = await fetchImpl(url, {
|
|
979
|
+
...init,
|
|
980
|
+
headers: { ...init.headers, ...auth }
|
|
981
|
+
});
|
|
982
|
+
return { response, authenticated: auth.Authorization !== void 0 };
|
|
983
|
+
};
|
|
984
|
+
const first = await send();
|
|
985
|
+
if (first.response.status === 401 && first.authenticated) {
|
|
986
|
+
clearPulseToken();
|
|
987
|
+
return (await send()).response;
|
|
988
|
+
}
|
|
989
|
+
return first.response;
|
|
990
|
+
}
|
|
991
|
+
|
|
910
992
|
// src/client.ts
|
|
911
993
|
var DEFAULT_ENDPOINT = "https://api.patchstack.com/monitor/pulse/manifest";
|
|
912
994
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
@@ -923,7 +1005,7 @@ async function postManifest(config, payload) {
|
|
|
923
1005
|
const timeoutMs = config.timeoutMs;
|
|
924
1006
|
let response;
|
|
925
1007
|
try {
|
|
926
|
-
response = await
|
|
1008
|
+
response = await pulseFetch(config, url, {
|
|
927
1009
|
method: "POST",
|
|
928
1010
|
headers: {
|
|
929
1011
|
"Content-Type": "application/json",
|
|
@@ -1015,8 +1097,12 @@ async function resolveConfig(options) {
|
|
|
1015
1097
|
"CONFIG_MISSING"
|
|
1016
1098
|
);
|
|
1017
1099
|
}
|
|
1100
|
+
const apiKeyRaw = fromEnv.apiKey ?? fromFile.apiKey ?? null;
|
|
1101
|
+
const pulseAuthRaw = fromEnv.pulseAuth ?? fromFile.pulseAuth ?? apiKeyRaw;
|
|
1018
1102
|
return {
|
|
1019
1103
|
siteUuid: siteUuid === null || siteUuid.length === 0 ? null : siteUuid,
|
|
1104
|
+
apiKey: apiKeyRaw === null || apiKeyRaw.length === 0 ? null : apiKeyRaw,
|
|
1105
|
+
pulseAuth: pulseAuthRaw === null || pulseAuthRaw.length === 0 ? null : pulseAuthRaw,
|
|
1020
1106
|
endpoint,
|
|
1021
1107
|
timeoutMs,
|
|
1022
1108
|
environment,
|
|
@@ -1033,6 +1119,14 @@ async function persistSiteUuid(cwd, siteUuid) {
|
|
|
1033
1119
|
const existing = await readConfigFile(cwd);
|
|
1034
1120
|
return writeConfigFile(cwd, { ...existing, siteUuid });
|
|
1035
1121
|
}
|
|
1122
|
+
async function persistApiKey(cwd, apiKey) {
|
|
1123
|
+
const existing = await readConfigFile(cwd);
|
|
1124
|
+
return writeConfigFile(cwd, { ...existing, apiKey });
|
|
1125
|
+
}
|
|
1126
|
+
async function persistPulseAuth(cwd, pulseAuth) {
|
|
1127
|
+
const existing = await readConfigFile(cwd);
|
|
1128
|
+
return writeConfigFile(cwd, { ...existing, pulseAuth });
|
|
1129
|
+
}
|
|
1036
1130
|
async function readConfigFile(cwd) {
|
|
1037
1131
|
const target = path6.join(cwd, CONFIG_FILENAME);
|
|
1038
1132
|
let raw;
|
|
@@ -1074,6 +1168,8 @@ function readEnv() {
|
|
|
1074
1168
|
const environmentRaw = process.env.PATCHSTACK_ENVIRONMENT;
|
|
1075
1169
|
return {
|
|
1076
1170
|
siteUuid: process.env.PATCHSTACK_SITE_UUID ?? void 0,
|
|
1171
|
+
apiKey: process.env.PATCHSTACK_API_KEY ?? void 0,
|
|
1172
|
+
pulseAuth: process.env.PATCHSTACK_PULSE_AUTH ?? void 0,
|
|
1077
1173
|
endpoint: process.env.PATCHSTACK_ENDPOINT ?? void 0,
|
|
1078
1174
|
timeoutMs,
|
|
1079
1175
|
environment: environmentRaw !== void 0 && environmentRaw.length > 0 ? environmentRaw : void 0
|
|
@@ -1242,6 +1338,10 @@ async function scanAndReport(options = {}) {
|
|
|
1242
1338
|
if (config.siteUuid === null && response.uuid !== void 0 && response.uuid.length > 0) {
|
|
1243
1339
|
await persistSiteUuid(cwd, response.uuid);
|
|
1244
1340
|
}
|
|
1341
|
+
if (typeof response.api_key === "string" && response.api_key.length > 0) {
|
|
1342
|
+
await persistApiKey(cwd, response.api_key);
|
|
1343
|
+
await persistPulseAuth(cwd, response.api_key);
|
|
1344
|
+
}
|
|
1245
1345
|
return {
|
|
1246
1346
|
manifest,
|
|
1247
1347
|
response,
|
|
@@ -1267,6 +1367,8 @@ export {
|
|
|
1267
1367
|
ensureWidgetInHtml,
|
|
1268
1368
|
findSourceShell,
|
|
1269
1369
|
isEmptyStack,
|
|
1370
|
+
persistApiKey,
|
|
1371
|
+
persistPulseAuth,
|
|
1270
1372
|
persistSiteUuid,
|
|
1271
1373
|
postManifest,
|
|
1272
1374
|
resolveConfig,
|