@particle-academy/fancy-connector-core 0.8.0 → 0.9.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/CHANGELOG.md +63 -0
- package/dist/index.cjs +46 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +63 -6
- package/dist/index.d.ts +63 -6
- package/dist/index.js +45 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -2333,18 +2333,47 @@ type WebhookVerification = {
|
|
|
2333
2333
|
reason: string;
|
|
2334
2334
|
};
|
|
2335
2335
|
type HmacScheme = {
|
|
2336
|
+
/**
|
|
2337
|
+
* Optional and always `"hmac"`: every scheme written before 0.8.0 omits it
|
|
2338
|
+
* and still means HMAC. It exists so `verifyDelivery` dispatches on a NAMED
|
|
2339
|
+
* kind — `"shared-token"`, `"hmac"` or absent — and refuses any other value
|
|
2340
|
+
* by name, rather than treating "has no kind" as HMAC forever. (Fancy's
|
|
2341
|
+
* alignment review of 0.8.0: a third scheme that forgot its kind would
|
|
2342
|
+
* otherwise be verified as HMAC, silently.)
|
|
2343
|
+
*/
|
|
2344
|
+
kind?: "hmac";
|
|
2336
2345
|
/** Hash to use. */
|
|
2337
2346
|
algorithm: "SHA-256" | "SHA-1" | "SHA-512";
|
|
2338
2347
|
/**
|
|
2339
2348
|
* Build the exact string that gets signed. Providers differ here more than
|
|
2340
2349
|
* anywhere else — Stripe signs `${timestamp}.${body}`, Slack signs
|
|
2341
|
-
* `v0:${timestamp}:${body}`, GitHub signs the body alone
|
|
2350
|
+
* `v0:${timestamp}:${body}`, GitHub signs the body alone, and Svix signs
|
|
2351
|
+
* `${id}.${timestamp}.${body}` where `id` is the delivery's own id header.
|
|
2342
2352
|
*/
|
|
2343
|
-
payload: (raw: string, timestamp?: string) => string;
|
|
2353
|
+
payload: (raw: string, timestamp?: string, id?: string) => string;
|
|
2344
2354
|
/** Seconds a delivery stays acceptable. */
|
|
2345
2355
|
tolerance?: number;
|
|
2346
2356
|
/** Encoding of the signature the provider sends. */
|
|
2347
2357
|
encoding?: "hex" | "base64";
|
|
2358
|
+
/**
|
|
2359
|
+
* How the SECRET is spelled. `utf8` (the default, and every provider before
|
|
2360
|
+
* Svix): the key is the text's bytes. `base64`: the key is the DECODED
|
|
2361
|
+
* bytes — Svix hands out `whsec_<base64>`, and half of the decoded bytes are
|
|
2362
|
+
* not valid UTF-8, so encoding the text would sign with the wrong key and
|
|
2363
|
+
* fail exactly like a wrong secret.
|
|
2364
|
+
*/
|
|
2365
|
+
secretEncoding?: "utf8" | "base64";
|
|
2366
|
+
/** A prefix to strip before decoding (`whsec_`). Its absence is a refusal, never a guess. */
|
|
2367
|
+
secretPrefix?: string;
|
|
2368
|
+
};
|
|
2369
|
+
/** The HMAC key a scheme's secret spells, or the reason it cannot be one. */
|
|
2370
|
+
declare function secretKeyBytes(secret: string, options?: {
|
|
2371
|
+
secretEncoding?: "utf8" | "base64";
|
|
2372
|
+
secretPrefix?: string;
|
|
2373
|
+
}): {
|
|
2374
|
+
bytes: Uint8Array;
|
|
2375
|
+
} | {
|
|
2376
|
+
reason: string;
|
|
2348
2377
|
};
|
|
2349
2378
|
/**
|
|
2350
2379
|
* Verify an HMAC-signed delivery.
|
|
@@ -2355,15 +2384,33 @@ type HmacScheme = {
|
|
|
2355
2384
|
*/
|
|
2356
2385
|
declare function verifyHmac(options: {
|
|
2357
2386
|
raw: string;
|
|
2358
|
-
|
|
2387
|
+
/**
|
|
2388
|
+
* The signature(s) the delivery carried. A LIST when the provider sends
|
|
2389
|
+
* several — Stripe signs once per active secret while a secret is rolled
|
|
2390
|
+
* and Svix's header "could be any number of signatures" — and the delivery
|
|
2391
|
+
* is accepted when ANY matches. A first-only rule fails every delivery
|
|
2392
|
+
* whose first signature came from the new secret, for the whole roll, and
|
|
2393
|
+
* it reads exactly like a wrong secret.
|
|
2394
|
+
*/
|
|
2395
|
+
signature: string | string[] | undefined;
|
|
2359
2396
|
secret: string | undefined;
|
|
2360
2397
|
scheme: HmacScheme;
|
|
2361
2398
|
timestamp?: string;
|
|
2399
|
+
/** The delivery's id, when the scheme signs one (Svix's `svix-id`). */
|
|
2400
|
+
id?: string;
|
|
2362
2401
|
/** Seconds since the epoch. Injected so tests are not clock-dependent. */
|
|
2363
2402
|
now?: number;
|
|
2364
2403
|
}): Promise<WebhookVerification>;
|
|
2365
|
-
/**
|
|
2366
|
-
|
|
2404
|
+
/**
|
|
2405
|
+
* HMAC of `payload` under `secret`, hex or base64 encoded. `options` says how
|
|
2406
|
+
* the secret is spelled (see `HmacScheme.secretEncoding`); a secret that
|
|
2407
|
+
* cannot be a key THROWS here — signing has no result to carry a reason in —
|
|
2408
|
+
* while `verifyHmac` names it in its result before ever calling this.
|
|
2409
|
+
*/
|
|
2410
|
+
declare function hmac(secret: string, payload: string, algorithm: HmacScheme["algorithm"], encoding?: "hex" | "base64", options?: {
|
|
2411
|
+
secretEncoding?: "utf8" | "base64";
|
|
2412
|
+
secretPrefix?: string;
|
|
2413
|
+
}): Promise<string>;
|
|
2367
2414
|
/**
|
|
2368
2415
|
* Compare two strings without leaking where they diverge.
|
|
2369
2416
|
*
|
|
@@ -2494,13 +2541,23 @@ type HmacVerificationSpec = {
|
|
|
2494
2541
|
signatureHeader: string;
|
|
2495
2542
|
/** Header carrying the timestamp, when the scheme signs one. */
|
|
2496
2543
|
timestampHeader?: string;
|
|
2544
|
+
/**
|
|
2545
|
+
* Header carrying the delivery's ID, when the scheme signs one — Svix
|
|
2546
|
+
* signs `${svix-id}.${svix-timestamp}.${body}`. A declared id header the
|
|
2547
|
+
* delivery does not carry is a refusal, never a payload with a hole in it.
|
|
2548
|
+
*/
|
|
2549
|
+
idHeader?: string;
|
|
2497
2550
|
scheme: HmacScheme;
|
|
2498
2551
|
/**
|
|
2499
2552
|
* Some schemes pack the timestamp INTO the signature header
|
|
2500
2553
|
* (Stripe: `t=…,v1=…`). Given the raw header value, return the parts.
|
|
2554
|
+
* `signatures` carries EVERY signature the header held (a provider rolling
|
|
2555
|
+
* a secret sends one per active secret); `signature` alone is the 0.8.x
|
|
2556
|
+
* shape and still means one.
|
|
2501
2557
|
*/
|
|
2502
2558
|
parse?: (raw: string) => {
|
|
2503
2559
|
signature?: string;
|
|
2560
|
+
signatures?: string[];
|
|
2504
2561
|
timestamp?: string;
|
|
2505
2562
|
};
|
|
2506
2563
|
/** A challenge the provider makes before it will deliver anything. */
|
|
@@ -2546,4 +2603,4 @@ declare function verifyDelivery(trigger: TriggerDescriptor, delivery: InboundDel
|
|
|
2546
2603
|
*/
|
|
2547
2604
|
declare function triggerEvent(trigger: TriggerDescriptor, connection: ResolvedConnection, injected: unknown, config: Record<string, unknown>): unknown;
|
|
2548
2605
|
|
|
2549
|
-
export { AMBIGUOUS_REFUSAL, type ApiContract, type Attempt, type ByteRange, CANONICAL_METRICS, CONNECTOR_API_VERSION, CONNECTOR_MODES, CREDENTIAL_SCOPES, type CallOptions, type CallResult, type Capabilities, type Catalogue, type ChainLinks, type ChainOutcome, type ChainRef, type ChallengeHandshake, type Citation, type Classified, type ConnectionCredentials, type ConnectionHost, type ConnectionSpec, type Connector, ConnectorAmbiguous, ConnectorApiMismatch, ConnectorAuthError, ConnectorConfigError, ConnectorError, type ConnectorErrorContext, type ConnectorFaker, ConnectorIdempotencyExpiredError, type ConnectorMode, ConnectorModeError, ConnectorRateLimited, type ConnectorRequest, ConnectorRequestError, type ConnectorResult, ConnectorTransient, ConnectorUnreachable, type ContractOperation, type CredentialField, type CredentialScope, DEFAULT_IDEMPOTENCY_WINDOW_SECONDS, DEFAULT_RETRY, type DeliveryDeclaration, type DeliveryMechanism, type DeliveryOutcome, type DriftFinding, type DriftReport, EXPIRES_AT_UNITS, type ExpiresAtUnit, FAKE_EPOCH, type FailureKind, type FakeRequest, type FakeValues, type HmacScheme, type HmacVerificationSpec, type HostEnvironment, type IdempotencyOptions, type InboundDelivery, type LeaseAction, type LeaseDeclaration, type LeaseState, MAX_IDEMPOTENCY_KEY_LENGTH, type MetricDescriptor, type MetricSample, type MimeAttachment, type MimeHeader, type MimeMessage, type MimePart, type ModeInputs, NO_IDEMPOTENCY_KEY_WARNING, PROBLEM_SEVERITIES, type PreparedRequest, type ProbeOutcome, type ProbeReport, type ProbeResult, type ProbeSpec, type Problem, type ProviderAdapter, RENDERER_VERSION, REVIEW_STALE_DAYS, type RecordedShape, type RenderRules, type RenderedPayload, type RequestedMode, type ResolveOptions, type ResolvedConnection, type RetryPolicy, type RunIdentity, SANDBOX_KINDS, SUPPORTED_CONNECTOR_API, type SandboxKind, type Segment, type ServiceDescriptor, type SetupStep, type ShapeMismatch, type SharedTokenScheme, type SharedTokenVerificationSpec, type SpecSource, type SubscriptionLease, type TextUnit, type Transport, type TransportResponse, type TriggerDescriptor, type VerifyResult, type WebhookVerification, type WebhookVerificationSpec, assertConnectorApi, byteRangeOf, callConnector, capabilityProblems, checkAgainstOpenApi, checkAgainstRecordedShape, classifyError, classifyHttp, classifyStatus, classifyThrown, compareShape, connectionsFor, constantTimeEquals, deliver, fakeRequest, fakeValues, getConnectionHost, graphemes, handshakeResponse, header, hmac, httpFailure, idempotencyKeyFor, isEmptyPayload, isRemote, isSharedTokenScheme, isSharedTokenSpec, isUnconditionallyRetryable, leaseAction, leaseFromResponse, leaseRenewAt, leaseState, linkRanges, measure, parseMime, payloadHash, postChain, probe, providerProblems, providerSandboxIsSelectable, registerConnectionHost, registerTransport, render, reported, resetRateState, resolveConnection, resolveConnectorMode, respectRate, runIdentityFrom, runKeyFrom, runProbes, sandboxIsSelectable, sandboxRefusal, satisfiesMinimum, seedFrom, shapeOf, shouldRetry, sliceByteRange, splitToFit, subscriptionLease, triggerEvent, unchecked, utf8Length, verifyDelivery, verifyHmac, verifySharedToken, withResolvedLimit };
|
|
2606
|
+
export { AMBIGUOUS_REFUSAL, type ApiContract, type Attempt, type ByteRange, CANONICAL_METRICS, CONNECTOR_API_VERSION, CONNECTOR_MODES, CREDENTIAL_SCOPES, type CallOptions, type CallResult, type Capabilities, type Catalogue, type ChainLinks, type ChainOutcome, type ChainRef, type ChallengeHandshake, type Citation, type Classified, type ConnectionCredentials, type ConnectionHost, type ConnectionSpec, type Connector, ConnectorAmbiguous, ConnectorApiMismatch, ConnectorAuthError, ConnectorConfigError, ConnectorError, type ConnectorErrorContext, type ConnectorFaker, ConnectorIdempotencyExpiredError, type ConnectorMode, ConnectorModeError, ConnectorRateLimited, type ConnectorRequest, ConnectorRequestError, type ConnectorResult, ConnectorTransient, ConnectorUnreachable, type ContractOperation, type CredentialField, type CredentialScope, DEFAULT_IDEMPOTENCY_WINDOW_SECONDS, DEFAULT_RETRY, type DeliveryDeclaration, type DeliveryMechanism, type DeliveryOutcome, type DriftFinding, type DriftReport, EXPIRES_AT_UNITS, type ExpiresAtUnit, FAKE_EPOCH, type FailureKind, type FakeRequest, type FakeValues, type HmacScheme, type HmacVerificationSpec, type HostEnvironment, type IdempotencyOptions, type InboundDelivery, type LeaseAction, type LeaseDeclaration, type LeaseState, MAX_IDEMPOTENCY_KEY_LENGTH, type MetricDescriptor, type MetricSample, type MimeAttachment, type MimeHeader, type MimeMessage, type MimePart, type ModeInputs, NO_IDEMPOTENCY_KEY_WARNING, PROBLEM_SEVERITIES, type PreparedRequest, type ProbeOutcome, type ProbeReport, type ProbeResult, type ProbeSpec, type Problem, type ProviderAdapter, RENDERER_VERSION, REVIEW_STALE_DAYS, type RecordedShape, type RenderRules, type RenderedPayload, type RequestedMode, type ResolveOptions, type ResolvedConnection, type RetryPolicy, type RunIdentity, SANDBOX_KINDS, SUPPORTED_CONNECTOR_API, type SandboxKind, type Segment, type ServiceDescriptor, type SetupStep, type ShapeMismatch, type SharedTokenScheme, type SharedTokenVerificationSpec, type SpecSource, type SubscriptionLease, type TextUnit, type Transport, type TransportResponse, type TriggerDescriptor, type VerifyResult, type WebhookVerification, type WebhookVerificationSpec, assertConnectorApi, byteRangeOf, callConnector, capabilityProblems, checkAgainstOpenApi, checkAgainstRecordedShape, classifyError, classifyHttp, classifyStatus, classifyThrown, compareShape, connectionsFor, constantTimeEquals, deliver, fakeRequest, fakeValues, getConnectionHost, graphemes, handshakeResponse, header, hmac, httpFailure, idempotencyKeyFor, isEmptyPayload, isRemote, isSharedTokenScheme, isSharedTokenSpec, isUnconditionallyRetryable, leaseAction, leaseFromResponse, leaseRenewAt, leaseState, linkRanges, measure, parseMime, payloadHash, postChain, probe, providerProblems, providerSandboxIsSelectable, registerConnectionHost, registerTransport, render, reported, resetRateState, resolveConnection, resolveConnectorMode, respectRate, runIdentityFrom, runKeyFrom, runProbes, sandboxIsSelectable, sandboxRefusal, satisfiesMinimum, secretKeyBytes, seedFrom, shapeOf, shouldRetry, sliceByteRange, splitToFit, subscriptionLease, triggerEvent, unchecked, utf8Length, verifyDelivery, verifyHmac, verifySharedToken, withResolvedLimit };
|
package/dist/index.d.ts
CHANGED
|
@@ -2333,18 +2333,47 @@ type WebhookVerification = {
|
|
|
2333
2333
|
reason: string;
|
|
2334
2334
|
};
|
|
2335
2335
|
type HmacScheme = {
|
|
2336
|
+
/**
|
|
2337
|
+
* Optional and always `"hmac"`: every scheme written before 0.8.0 omits it
|
|
2338
|
+
* and still means HMAC. It exists so `verifyDelivery` dispatches on a NAMED
|
|
2339
|
+
* kind — `"shared-token"`, `"hmac"` or absent — and refuses any other value
|
|
2340
|
+
* by name, rather than treating "has no kind" as HMAC forever. (Fancy's
|
|
2341
|
+
* alignment review of 0.8.0: a third scheme that forgot its kind would
|
|
2342
|
+
* otherwise be verified as HMAC, silently.)
|
|
2343
|
+
*/
|
|
2344
|
+
kind?: "hmac";
|
|
2336
2345
|
/** Hash to use. */
|
|
2337
2346
|
algorithm: "SHA-256" | "SHA-1" | "SHA-512";
|
|
2338
2347
|
/**
|
|
2339
2348
|
* Build the exact string that gets signed. Providers differ here more than
|
|
2340
2349
|
* anywhere else — Stripe signs `${timestamp}.${body}`, Slack signs
|
|
2341
|
-
* `v0:${timestamp}:${body}`, GitHub signs the body alone
|
|
2350
|
+
* `v0:${timestamp}:${body}`, GitHub signs the body alone, and Svix signs
|
|
2351
|
+
* `${id}.${timestamp}.${body}` where `id` is the delivery's own id header.
|
|
2342
2352
|
*/
|
|
2343
|
-
payload: (raw: string, timestamp?: string) => string;
|
|
2353
|
+
payload: (raw: string, timestamp?: string, id?: string) => string;
|
|
2344
2354
|
/** Seconds a delivery stays acceptable. */
|
|
2345
2355
|
tolerance?: number;
|
|
2346
2356
|
/** Encoding of the signature the provider sends. */
|
|
2347
2357
|
encoding?: "hex" | "base64";
|
|
2358
|
+
/**
|
|
2359
|
+
* How the SECRET is spelled. `utf8` (the default, and every provider before
|
|
2360
|
+
* Svix): the key is the text's bytes. `base64`: the key is the DECODED
|
|
2361
|
+
* bytes — Svix hands out `whsec_<base64>`, and half of the decoded bytes are
|
|
2362
|
+
* not valid UTF-8, so encoding the text would sign with the wrong key and
|
|
2363
|
+
* fail exactly like a wrong secret.
|
|
2364
|
+
*/
|
|
2365
|
+
secretEncoding?: "utf8" | "base64";
|
|
2366
|
+
/** A prefix to strip before decoding (`whsec_`). Its absence is a refusal, never a guess. */
|
|
2367
|
+
secretPrefix?: string;
|
|
2368
|
+
};
|
|
2369
|
+
/** The HMAC key a scheme's secret spells, or the reason it cannot be one. */
|
|
2370
|
+
declare function secretKeyBytes(secret: string, options?: {
|
|
2371
|
+
secretEncoding?: "utf8" | "base64";
|
|
2372
|
+
secretPrefix?: string;
|
|
2373
|
+
}): {
|
|
2374
|
+
bytes: Uint8Array;
|
|
2375
|
+
} | {
|
|
2376
|
+
reason: string;
|
|
2348
2377
|
};
|
|
2349
2378
|
/**
|
|
2350
2379
|
* Verify an HMAC-signed delivery.
|
|
@@ -2355,15 +2384,33 @@ type HmacScheme = {
|
|
|
2355
2384
|
*/
|
|
2356
2385
|
declare function verifyHmac(options: {
|
|
2357
2386
|
raw: string;
|
|
2358
|
-
|
|
2387
|
+
/**
|
|
2388
|
+
* The signature(s) the delivery carried. A LIST when the provider sends
|
|
2389
|
+
* several — Stripe signs once per active secret while a secret is rolled
|
|
2390
|
+
* and Svix's header "could be any number of signatures" — and the delivery
|
|
2391
|
+
* is accepted when ANY matches. A first-only rule fails every delivery
|
|
2392
|
+
* whose first signature came from the new secret, for the whole roll, and
|
|
2393
|
+
* it reads exactly like a wrong secret.
|
|
2394
|
+
*/
|
|
2395
|
+
signature: string | string[] | undefined;
|
|
2359
2396
|
secret: string | undefined;
|
|
2360
2397
|
scheme: HmacScheme;
|
|
2361
2398
|
timestamp?: string;
|
|
2399
|
+
/** The delivery's id, when the scheme signs one (Svix's `svix-id`). */
|
|
2400
|
+
id?: string;
|
|
2362
2401
|
/** Seconds since the epoch. Injected so tests are not clock-dependent. */
|
|
2363
2402
|
now?: number;
|
|
2364
2403
|
}): Promise<WebhookVerification>;
|
|
2365
|
-
/**
|
|
2366
|
-
|
|
2404
|
+
/**
|
|
2405
|
+
* HMAC of `payload` under `secret`, hex or base64 encoded. `options` says how
|
|
2406
|
+
* the secret is spelled (see `HmacScheme.secretEncoding`); a secret that
|
|
2407
|
+
* cannot be a key THROWS here — signing has no result to carry a reason in —
|
|
2408
|
+
* while `verifyHmac` names it in its result before ever calling this.
|
|
2409
|
+
*/
|
|
2410
|
+
declare function hmac(secret: string, payload: string, algorithm: HmacScheme["algorithm"], encoding?: "hex" | "base64", options?: {
|
|
2411
|
+
secretEncoding?: "utf8" | "base64";
|
|
2412
|
+
secretPrefix?: string;
|
|
2413
|
+
}): Promise<string>;
|
|
2367
2414
|
/**
|
|
2368
2415
|
* Compare two strings without leaking where they diverge.
|
|
2369
2416
|
*
|
|
@@ -2494,13 +2541,23 @@ type HmacVerificationSpec = {
|
|
|
2494
2541
|
signatureHeader: string;
|
|
2495
2542
|
/** Header carrying the timestamp, when the scheme signs one. */
|
|
2496
2543
|
timestampHeader?: string;
|
|
2544
|
+
/**
|
|
2545
|
+
* Header carrying the delivery's ID, when the scheme signs one — Svix
|
|
2546
|
+
* signs `${svix-id}.${svix-timestamp}.${body}`. A declared id header the
|
|
2547
|
+
* delivery does not carry is a refusal, never a payload with a hole in it.
|
|
2548
|
+
*/
|
|
2549
|
+
idHeader?: string;
|
|
2497
2550
|
scheme: HmacScheme;
|
|
2498
2551
|
/**
|
|
2499
2552
|
* Some schemes pack the timestamp INTO the signature header
|
|
2500
2553
|
* (Stripe: `t=…,v1=…`). Given the raw header value, return the parts.
|
|
2554
|
+
* `signatures` carries EVERY signature the header held (a provider rolling
|
|
2555
|
+
* a secret sends one per active secret); `signature` alone is the 0.8.x
|
|
2556
|
+
* shape and still means one.
|
|
2501
2557
|
*/
|
|
2502
2558
|
parse?: (raw: string) => {
|
|
2503
2559
|
signature?: string;
|
|
2560
|
+
signatures?: string[];
|
|
2504
2561
|
timestamp?: string;
|
|
2505
2562
|
};
|
|
2506
2563
|
/** A challenge the provider makes before it will deliver anything. */
|
|
@@ -2546,4 +2603,4 @@ declare function verifyDelivery(trigger: TriggerDescriptor, delivery: InboundDel
|
|
|
2546
2603
|
*/
|
|
2547
2604
|
declare function triggerEvent(trigger: TriggerDescriptor, connection: ResolvedConnection, injected: unknown, config: Record<string, unknown>): unknown;
|
|
2548
2605
|
|
|
2549
|
-
export { AMBIGUOUS_REFUSAL, type ApiContract, type Attempt, type ByteRange, CANONICAL_METRICS, CONNECTOR_API_VERSION, CONNECTOR_MODES, CREDENTIAL_SCOPES, type CallOptions, type CallResult, type Capabilities, type Catalogue, type ChainLinks, type ChainOutcome, type ChainRef, type ChallengeHandshake, type Citation, type Classified, type ConnectionCredentials, type ConnectionHost, type ConnectionSpec, type Connector, ConnectorAmbiguous, ConnectorApiMismatch, ConnectorAuthError, ConnectorConfigError, ConnectorError, type ConnectorErrorContext, type ConnectorFaker, ConnectorIdempotencyExpiredError, type ConnectorMode, ConnectorModeError, ConnectorRateLimited, type ConnectorRequest, ConnectorRequestError, type ConnectorResult, ConnectorTransient, ConnectorUnreachable, type ContractOperation, type CredentialField, type CredentialScope, DEFAULT_IDEMPOTENCY_WINDOW_SECONDS, DEFAULT_RETRY, type DeliveryDeclaration, type DeliveryMechanism, type DeliveryOutcome, type DriftFinding, type DriftReport, EXPIRES_AT_UNITS, type ExpiresAtUnit, FAKE_EPOCH, type FailureKind, type FakeRequest, type FakeValues, type HmacScheme, type HmacVerificationSpec, type HostEnvironment, type IdempotencyOptions, type InboundDelivery, type LeaseAction, type LeaseDeclaration, type LeaseState, MAX_IDEMPOTENCY_KEY_LENGTH, type MetricDescriptor, type MetricSample, type MimeAttachment, type MimeHeader, type MimeMessage, type MimePart, type ModeInputs, NO_IDEMPOTENCY_KEY_WARNING, PROBLEM_SEVERITIES, type PreparedRequest, type ProbeOutcome, type ProbeReport, type ProbeResult, type ProbeSpec, type Problem, type ProviderAdapter, RENDERER_VERSION, REVIEW_STALE_DAYS, type RecordedShape, type RenderRules, type RenderedPayload, type RequestedMode, type ResolveOptions, type ResolvedConnection, type RetryPolicy, type RunIdentity, SANDBOX_KINDS, SUPPORTED_CONNECTOR_API, type SandboxKind, type Segment, type ServiceDescriptor, type SetupStep, type ShapeMismatch, type SharedTokenScheme, type SharedTokenVerificationSpec, type SpecSource, type SubscriptionLease, type TextUnit, type Transport, type TransportResponse, type TriggerDescriptor, type VerifyResult, type WebhookVerification, type WebhookVerificationSpec, assertConnectorApi, byteRangeOf, callConnector, capabilityProblems, checkAgainstOpenApi, checkAgainstRecordedShape, classifyError, classifyHttp, classifyStatus, classifyThrown, compareShape, connectionsFor, constantTimeEquals, deliver, fakeRequest, fakeValues, getConnectionHost, graphemes, handshakeResponse, header, hmac, httpFailure, idempotencyKeyFor, isEmptyPayload, isRemote, isSharedTokenScheme, isSharedTokenSpec, isUnconditionallyRetryable, leaseAction, leaseFromResponse, leaseRenewAt, leaseState, linkRanges, measure, parseMime, payloadHash, postChain, probe, providerProblems, providerSandboxIsSelectable, registerConnectionHost, registerTransport, render, reported, resetRateState, resolveConnection, resolveConnectorMode, respectRate, runIdentityFrom, runKeyFrom, runProbes, sandboxIsSelectable, sandboxRefusal, satisfiesMinimum, seedFrom, shapeOf, shouldRetry, sliceByteRange, splitToFit, subscriptionLease, triggerEvent, unchecked, utf8Length, verifyDelivery, verifyHmac, verifySharedToken, withResolvedLimit };
|
|
2606
|
+
export { AMBIGUOUS_REFUSAL, type ApiContract, type Attempt, type ByteRange, CANONICAL_METRICS, CONNECTOR_API_VERSION, CONNECTOR_MODES, CREDENTIAL_SCOPES, type CallOptions, type CallResult, type Capabilities, type Catalogue, type ChainLinks, type ChainOutcome, type ChainRef, type ChallengeHandshake, type Citation, type Classified, type ConnectionCredentials, type ConnectionHost, type ConnectionSpec, type Connector, ConnectorAmbiguous, ConnectorApiMismatch, ConnectorAuthError, ConnectorConfigError, ConnectorError, type ConnectorErrorContext, type ConnectorFaker, ConnectorIdempotencyExpiredError, type ConnectorMode, ConnectorModeError, ConnectorRateLimited, type ConnectorRequest, ConnectorRequestError, type ConnectorResult, ConnectorTransient, ConnectorUnreachable, type ContractOperation, type CredentialField, type CredentialScope, DEFAULT_IDEMPOTENCY_WINDOW_SECONDS, DEFAULT_RETRY, type DeliveryDeclaration, type DeliveryMechanism, type DeliveryOutcome, type DriftFinding, type DriftReport, EXPIRES_AT_UNITS, type ExpiresAtUnit, FAKE_EPOCH, type FailureKind, type FakeRequest, type FakeValues, type HmacScheme, type HmacVerificationSpec, type HostEnvironment, type IdempotencyOptions, type InboundDelivery, type LeaseAction, type LeaseDeclaration, type LeaseState, MAX_IDEMPOTENCY_KEY_LENGTH, type MetricDescriptor, type MetricSample, type MimeAttachment, type MimeHeader, type MimeMessage, type MimePart, type ModeInputs, NO_IDEMPOTENCY_KEY_WARNING, PROBLEM_SEVERITIES, type PreparedRequest, type ProbeOutcome, type ProbeReport, type ProbeResult, type ProbeSpec, type Problem, type ProviderAdapter, RENDERER_VERSION, REVIEW_STALE_DAYS, type RecordedShape, type RenderRules, type RenderedPayload, type RequestedMode, type ResolveOptions, type ResolvedConnection, type RetryPolicy, type RunIdentity, SANDBOX_KINDS, SUPPORTED_CONNECTOR_API, type SandboxKind, type Segment, type ServiceDescriptor, type SetupStep, type ShapeMismatch, type SharedTokenScheme, type SharedTokenVerificationSpec, type SpecSource, type SubscriptionLease, type TextUnit, type Transport, type TransportResponse, type TriggerDescriptor, type VerifyResult, type WebhookVerification, type WebhookVerificationSpec, assertConnectorApi, byteRangeOf, callConnector, capabilityProblems, checkAgainstOpenApi, checkAgainstRecordedShape, classifyError, classifyHttp, classifyStatus, classifyThrown, compareShape, connectionsFor, constantTimeEquals, deliver, fakeRequest, fakeValues, getConnectionHost, graphemes, handshakeResponse, header, hmac, httpFailure, idempotencyKeyFor, isEmptyPayload, isRemote, isSharedTokenScheme, isSharedTokenSpec, isUnconditionallyRetryable, leaseAction, leaseFromResponse, leaseRenewAt, leaseState, linkRanges, measure, parseMime, payloadHash, postChain, probe, providerProblems, providerSandboxIsSelectable, registerConnectionHost, registerTransport, render, reported, resetRateState, resolveConnection, resolveConnectorMode, respectRate, runIdentityFrom, runKeyFrom, runProbes, sandboxIsSelectable, sandboxRefusal, satisfiesMinimum, secretKeyBytes, seedFrom, shapeOf, shouldRetry, sliceByteRange, splitToFit, subscriptionLease, triggerEvent, unchecked, utf8Length, verifyDelivery, verifyHmac, verifySharedToken, withResolvedLimit };
|
package/dist/index.js
CHANGED
|
@@ -1557,12 +1557,35 @@ var PROBLEM_SEVERITIES = ["block", "warn"];
|
|
|
1557
1557
|
var CANONICAL_METRICS = ["like", "share", "reply", "quote", "view"];
|
|
1558
1558
|
|
|
1559
1559
|
// src/webhook.ts
|
|
1560
|
+
function secretKeyBytes(secret, options = {}) {
|
|
1561
|
+
let material = secret;
|
|
1562
|
+
if (options.secretPrefix !== void 0) {
|
|
1563
|
+
if (!material.startsWith(options.secretPrefix)) {
|
|
1564
|
+
return { reason: `signing secret does not start with ${JSON.stringify(options.secretPrefix)}` };
|
|
1565
|
+
}
|
|
1566
|
+
material = material.slice(options.secretPrefix.length);
|
|
1567
|
+
}
|
|
1568
|
+
if ((options.secretEncoding ?? "utf8") === "base64") {
|
|
1569
|
+
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(material) || material.length % 4 !== 0) {
|
|
1570
|
+
return { reason: "signing secret is not valid base64" };
|
|
1571
|
+
}
|
|
1572
|
+
try {
|
|
1573
|
+
return { bytes: Uint8Array.from(atob(material), (c) => c.charCodeAt(0)) };
|
|
1574
|
+
} catch {
|
|
1575
|
+
return { reason: "signing secret is not valid base64" };
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
return { bytes: new TextEncoder().encode(material) };
|
|
1579
|
+
}
|
|
1560
1580
|
async function verifyHmac(options) {
|
|
1561
|
-
const { raw,
|
|
1581
|
+
const { raw, secret, scheme, timestamp, id } = options;
|
|
1582
|
+
const signatures = (Array.isArray(options.signature) ? options.signature : [options.signature]).filter(
|
|
1583
|
+
(s) => typeof s === "string" && s !== ""
|
|
1584
|
+
);
|
|
1562
1585
|
if (!secret) {
|
|
1563
1586
|
return { ok: false, reason: "no signing secret configured for this trigger" };
|
|
1564
1587
|
}
|
|
1565
|
-
if (
|
|
1588
|
+
if (signatures.length === 0) return { ok: false, reason: "delivery carried no signature header" };
|
|
1566
1589
|
if (scheme.tolerance !== void 0) {
|
|
1567
1590
|
if (!timestamp) return { ok: false, reason: "delivery carried no timestamp header" };
|
|
1568
1591
|
const sent = Number(timestamp);
|
|
@@ -1572,20 +1595,24 @@ async function verifyHmac(options) {
|
|
|
1572
1595
|
return { ok: false, reason: `delivery is outside the ${scheme.tolerance}s replay window` };
|
|
1573
1596
|
}
|
|
1574
1597
|
}
|
|
1575
|
-
const
|
|
1576
|
-
|
|
1598
|
+
const key = secretKeyBytes(secret, scheme);
|
|
1599
|
+
if ("reason" in key) return { ok: false, reason: key.reason };
|
|
1600
|
+
const expected = await hmac(secret, scheme.payload(raw, timestamp, id), scheme.algorithm, scheme.encoding ?? "hex", scheme);
|
|
1601
|
+
return signatures.some((candidate) => constantTimeEquals(expected, candidate)) ? { ok: true } : { ok: false, reason: "signature did not match" };
|
|
1577
1602
|
}
|
|
1578
|
-
async function hmac(secret, payload, algorithm, encoding = "hex") {
|
|
1603
|
+
async function hmac(secret, payload, algorithm, encoding = "hex", options = {}) {
|
|
1579
1604
|
const subtle = globalThis.crypto?.subtle;
|
|
1580
1605
|
if (!subtle) {
|
|
1581
1606
|
throw new Error(
|
|
1582
1607
|
"WebCrypto is not available in this runtime, so webhook signatures cannot be verified. Refusing to accept deliveries unverified."
|
|
1583
1608
|
);
|
|
1584
1609
|
}
|
|
1610
|
+
const material = secretKeyBytes(secret, options);
|
|
1611
|
+
if ("reason" in material) throw new Error(material.reason);
|
|
1585
1612
|
const encoder2 = new TextEncoder();
|
|
1586
1613
|
const key = await subtle.importKey(
|
|
1587
1614
|
"raw",
|
|
1588
|
-
|
|
1615
|
+
material.bytes,
|
|
1589
1616
|
{ name: "HMAC", hash: algorithm },
|
|
1590
1617
|
false,
|
|
1591
1618
|
["sign"]
|
|
@@ -1676,15 +1703,25 @@ async function verifyDelivery(trigger, delivery, secret, now) {
|
|
|
1676
1703
|
if (isSharedTokenSpec(spec)) {
|
|
1677
1704
|
return verifySharedToken({ raw: delivery.raw, headers: delivery.headers, secret, scheme: spec.scheme });
|
|
1678
1705
|
}
|
|
1706
|
+
const kind = spec.scheme.kind ?? "hmac";
|
|
1707
|
+
if (kind !== "hmac") {
|
|
1708
|
+
return {
|
|
1709
|
+
ok: false,
|
|
1710
|
+
reason: `${trigger.service}.${trigger.operation} declares a verification scheme "${kind}" this runtime does not know \u2014 refusing rather than guessing.`
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1679
1713
|
const rawHeader = header2(delivery.headers, spec.signatureHeader);
|
|
1680
1714
|
const parsed = spec.parse && rawHeader ? spec.parse(rawHeader) : { signature: rawHeader };
|
|
1681
1715
|
const timestamp = parsed.timestamp ?? (spec.timestampHeader ? header2(delivery.headers, spec.timestampHeader) : void 0);
|
|
1716
|
+
const id = spec.idHeader ? header2(delivery.headers, spec.idHeader) : void 0;
|
|
1717
|
+
if (spec.idHeader && !id) return { ok: false, reason: "delivery carried no id header" };
|
|
1682
1718
|
return verifyHmac({
|
|
1683
1719
|
raw: delivery.raw,
|
|
1684
|
-
signature: parsed.signature,
|
|
1720
|
+
signature: parsed.signatures ?? parsed.signature,
|
|
1685
1721
|
secret,
|
|
1686
1722
|
scheme: spec.scheme,
|
|
1687
1723
|
timestamp,
|
|
1724
|
+
id,
|
|
1688
1725
|
...now === void 0 ? {} : { now }
|
|
1689
1726
|
});
|
|
1690
1727
|
}
|
|
@@ -1788,6 +1825,7 @@ export {
|
|
|
1788
1825
|
sandboxIsSelectable,
|
|
1789
1826
|
sandboxRefusal,
|
|
1790
1827
|
satisfiesMinimum,
|
|
1828
|
+
secretKeyBytes,
|
|
1791
1829
|
seedFrom,
|
|
1792
1830
|
shapeOf,
|
|
1793
1831
|
shouldRetry,
|