@particle-academy/fancy-connector-core 0.13.0 → 0.14.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 +36 -0
- package/README.md +6 -1
- package/dist/index.cjs +93 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -1
- package/dist/index.d.ts +67 -1
- package/dist/index.js +90 -22
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -916,6 +916,72 @@ type ConnectorResult<T = unknown> = {
|
|
|
916
916
|
declare function registerTransport(next: Transport | null): void;
|
|
917
917
|
declare function callConnector<T = unknown>(service: ServiceDescriptor, options: CallOptions): Promise<ConnectorResult<T>>;
|
|
918
918
|
|
|
919
|
+
/**
|
|
920
|
+
* A read that resumes from a HOST-HELD cursor, and pages.
|
|
921
|
+
*
|
|
922
|
+
* Gmail's push and Drive's channel notifications carry no changes: they say
|
|
923
|
+
* "something moved", and the follow-up read fetches what did, starting from
|
|
924
|
+
* the position the HOST stored last time (Gmail's `startHistoryId`, Drive's
|
|
925
|
+
* `pageToken`). Reading from the delivery's own position instead misses the
|
|
926
|
+
* very change that caused it. The package holds no state: the host stores the
|
|
927
|
+
* cursor, passes it in, and persists `cursor.next` when the run succeeds.
|
|
928
|
+
*
|
|
929
|
+
* The PHP twin is `CursorRead::read`; both read `fixtures/cursor-read/`.
|
|
930
|
+
*
|
|
931
|
+
* The decisions, each pinned by a case:
|
|
932
|
+
*
|
|
933
|
+
* - **`next` comes ONLY from the LAST page.** Gmail's `historyId` is the
|
|
934
|
+
* mailbox's CURRENT one on every page, and Google says to store it only "if
|
|
935
|
+
* you receive no nextPageToken". Taking it after page one would skip every
|
|
936
|
+
* page not yet read, silently.
|
|
937
|
+
* - **Too many pages is refused** (`cursor-overflow`), never a partial read
|
|
938
|
+
* with a cursor that skips the rest. The host's answer is a bounded resync.
|
|
939
|
+
* - **The provider's own "cursor out of range"** (`expiredStatus`, Gmail's
|
|
940
|
+
* 404) is `cursor-expired`; every OTHER failure is rethrown unchanged, so a
|
|
941
|
+
* 500 is never mistaken for a lapse.
|
|
942
|
+
* - **No stored cursor is `cursor-missing`**, and the provider is not called:
|
|
943
|
+
* a read with no starting point is a read from the beginning of time.
|
|
944
|
+
* - `collect` absent is `[]` (Gmail omits `history` when nothing changed); not
|
|
945
|
+
* a list is `bad-page`. The cursor and `next` are strings: history ids are
|
|
946
|
+
* uint64.
|
|
947
|
+
*/
|
|
948
|
+
declare const CURSOR_READ_REASONS: readonly ["cursor-missing", "cursor-expired", "cursor-overflow", "bad-page"];
|
|
949
|
+
type CursorReadReason = (typeof CURSOR_READ_REASONS)[number];
|
|
950
|
+
type CursorReadSpec = {
|
|
951
|
+
/** The read's parameter the stored cursor fills (Gmail: `startHistoryId`). */
|
|
952
|
+
param: string;
|
|
953
|
+
/** Where the NEXT cursor is read in the last page's data (Gmail: `historyId`). */
|
|
954
|
+
advanceFrom: string;
|
|
955
|
+
/** Paging, when the read pages (Gmail: `pageToken` / `nextPageToken`, `history`). */
|
|
956
|
+
page?: {
|
|
957
|
+
param: string;
|
|
958
|
+
from: string;
|
|
959
|
+
collect: string;
|
|
960
|
+
maxPages: number;
|
|
961
|
+
};
|
|
962
|
+
/** The status the provider answers for a cursor out of range (Gmail: 404). */
|
|
963
|
+
expiredStatus?: number;
|
|
964
|
+
};
|
|
965
|
+
type CursorReadResult = {
|
|
966
|
+
data: unknown;
|
|
967
|
+
cursor: {
|
|
968
|
+
used: string;
|
|
969
|
+
next: string | null;
|
|
970
|
+
};
|
|
971
|
+
};
|
|
972
|
+
/** Refused BY NAME; `reason` is the same string PHP's exception carries. */
|
|
973
|
+
declare class CursorReadError extends Error {
|
|
974
|
+
readonly reason: CursorReadReason;
|
|
975
|
+
/** The host's bounded resync, when the caller declared one (Gmail: `newer_than:7d`). */
|
|
976
|
+
readonly resyncQuery?: string | undefined;
|
|
977
|
+
constructor(reason: CursorReadReason, message: string,
|
|
978
|
+
/** The host's bounded resync, when the caller declared one (Gmail: `newer_than:7d`). */
|
|
979
|
+
resyncQuery?: string | undefined);
|
|
980
|
+
}
|
|
981
|
+
declare function readWithCursor(spec: CursorReadSpec, cursor: unknown, call: (params: Record<string, string>) => Promise<unknown>, options?: {
|
|
982
|
+
resyncQuery?: string;
|
|
983
|
+
}): Promise<CursorReadResult>;
|
|
984
|
+
|
|
919
985
|
/**
|
|
920
986
|
* API drift — being told the provider changed, rather than discovering it.
|
|
921
987
|
*
|
|
@@ -2946,4 +3012,4 @@ oidc?: OidcExpectation): Promise<WebhookVerification>;
|
|
|
2946
3012
|
*/
|
|
2947
3013
|
declare function triggerEvent(trigger: TriggerDescriptor, connection: ResolvedConnection, injected: unknown, config: Record<string, unknown>): unknown;
|
|
2948
3014
|
|
|
2949
|
-
export { AMBIGUOUS_REFUSAL, type ApiContract, type Attempt, type Attendee, 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, DELIVERY_DECODE_KINDS, type DeliveryDeclaration, type DeliveryDecode, type DeliveryMechanism, type DeliveryOutcome, type DeliveryRoute, type DriftFinding, type DriftReport, EXPIRES_AT_UNITS, type ExpiresAtUnit, FAKE_EPOCH, FORM_FIELD_JSON_REASONS, type FailureKind, type FakeRequest, type FakeValues, FormFieldJsonError, type FormFieldJsonReason, type HmacScheme, type HmacVerificationSpec, type HostEnvironment, type IdempotencyOptions, type InboundDelivery, type Invite, type InviteMethod, JWT_ALGORITHMS, type JoinTarget, type JoinTargetKind, type Jwk, type JwtVerification, 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, OIDC_JWT_SCHEME_KIND, type OidcExpectation, type OidcJwtScheme, type OidcJwtVerificationSpec, PROBLEM_SEVERITIES, PUBSUB_PUSH_REASONS, type PreparedRequest, type ProbeOutcome, type ProbeReport, type ProbeResult, type ProbeSpec, type Problem, type ProviderAdapter, PubSubPushError, type PubSubPushMessage, type PubSubPushReason, RENDERER_VERSION, REVIEW_STALE_DAYS, type RecordedShape, type RecurrenceRule, type RenderRules, type RenderedPayload, type RequestedMode, type ResolveOptions, type ResolvedConnection, type RetryPolicy, type RunIdentity, SANDBOX_KINDS, SIGNED_URI_RULES, SUPPORTED_CONNECTOR_API, type SandboxKind, type Segment, type ServiceDescriptor, type SetupStep, type ShapeMismatch, type SharedTokenScheme, type SharedTokenVerificationSpec, type SignedRequestLine, type SignedUriRule, type SpecSource, type SubscriptionLease, type TextUnit, type Transport, type TransportResponse, type TriggerDescriptor, type VerifyJwtOptions, type VerifyResult, type WebhookVerification, type WebhookVerificationSpec, assertConnectorApi, byteRangeOf, callConnector, capabilityProblems, checkAgainstOpenApi, checkAgainstRecordedShape, classifyError, classifyHttp, classifyStatus, classifyThrown, compareShape, connectionsFor, constantTimeEquals, decodeDelivery, decodeFormFieldJson, decodePubSubPush, deliver, fakeRequest, fakeValues, getConnectionHost, graphemes, handshakeResponse, header, hmac, httpFailure, idempotencyKeyFor, isEmptyPayload, isOidcJwtScheme, isOidcJwtSpec, isRemote, isSharedTokenScheme, isSharedTokenSpec, isUnconditionallyRetryable, joinTargets, leaseAction, leaseFromResponse, leaseRenewAt, leaseState, linkRanges, measure, nextOccurrence, normaliseSignedUri, parseInvite, 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, verifyJwt, verifyOidcDelivery, verifySharedToken, withResolvedLimit };
|
|
3015
|
+
export { AMBIGUOUS_REFUSAL, type ApiContract, type Attempt, type Attendee, type ByteRange, CANONICAL_METRICS, CONNECTOR_API_VERSION, CONNECTOR_MODES, CREDENTIAL_SCOPES, CURSOR_READ_REASONS, 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, CursorReadError, type CursorReadReason, type CursorReadResult, type CursorReadSpec, DEFAULT_IDEMPOTENCY_WINDOW_SECONDS, DEFAULT_RETRY, DELIVERY_DECODE_KINDS, type DeliveryDeclaration, type DeliveryDecode, type DeliveryMechanism, type DeliveryOutcome, type DeliveryRoute, type DriftFinding, type DriftReport, EXPIRES_AT_UNITS, type ExpiresAtUnit, FAKE_EPOCH, FORM_FIELD_JSON_REASONS, type FailureKind, type FakeRequest, type FakeValues, FormFieldJsonError, type FormFieldJsonReason, type HmacScheme, type HmacVerificationSpec, type HostEnvironment, type IdempotencyOptions, type InboundDelivery, type Invite, type InviteMethod, JWT_ALGORITHMS, type JoinTarget, type JoinTargetKind, type Jwk, type JwtVerification, 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, OIDC_JWT_SCHEME_KIND, type OidcExpectation, type OidcJwtScheme, type OidcJwtVerificationSpec, PROBLEM_SEVERITIES, PUBSUB_PUSH_REASONS, type PreparedRequest, type ProbeOutcome, type ProbeReport, type ProbeResult, type ProbeSpec, type Problem, type ProviderAdapter, PubSubPushError, type PubSubPushMessage, type PubSubPushReason, RENDERER_VERSION, REVIEW_STALE_DAYS, type RecordedShape, type RecurrenceRule, type RenderRules, type RenderedPayload, type RequestedMode, type ResolveOptions, type ResolvedConnection, type RetryPolicy, type RunIdentity, SANDBOX_KINDS, SIGNED_URI_RULES, SUPPORTED_CONNECTOR_API, type SandboxKind, type Segment, type ServiceDescriptor, type SetupStep, type ShapeMismatch, type SharedTokenScheme, type SharedTokenVerificationSpec, type SignedRequestLine, type SignedUriRule, type SpecSource, type SubscriptionLease, type TextUnit, type Transport, type TransportResponse, type TriggerDescriptor, type VerifyJwtOptions, type VerifyResult, type WebhookVerification, type WebhookVerificationSpec, assertConnectorApi, byteRangeOf, callConnector, capabilityProblems, checkAgainstOpenApi, checkAgainstRecordedShape, classifyError, classifyHttp, classifyStatus, classifyThrown, compareShape, connectionsFor, constantTimeEquals, decodeDelivery, decodeFormFieldJson, decodePubSubPush, deliver, fakeRequest, fakeValues, getConnectionHost, graphemes, handshakeResponse, header, hmac, httpFailure, idempotencyKeyFor, isEmptyPayload, isOidcJwtScheme, isOidcJwtSpec, isRemote, isSharedTokenScheme, isSharedTokenSpec, isUnconditionallyRetryable, joinTargets, leaseAction, leaseFromResponse, leaseRenewAt, leaseState, linkRanges, measure, nextOccurrence, normaliseSignedUri, parseInvite, parseMime, payloadHash, postChain, probe, providerProblems, providerSandboxIsSelectable, readWithCursor, 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, verifyJwt, verifyOidcDelivery, verifySharedToken, withResolvedLimit };
|
package/dist/index.d.ts
CHANGED
|
@@ -916,6 +916,72 @@ type ConnectorResult<T = unknown> = {
|
|
|
916
916
|
declare function registerTransport(next: Transport | null): void;
|
|
917
917
|
declare function callConnector<T = unknown>(service: ServiceDescriptor, options: CallOptions): Promise<ConnectorResult<T>>;
|
|
918
918
|
|
|
919
|
+
/**
|
|
920
|
+
* A read that resumes from a HOST-HELD cursor, and pages.
|
|
921
|
+
*
|
|
922
|
+
* Gmail's push and Drive's channel notifications carry no changes: they say
|
|
923
|
+
* "something moved", and the follow-up read fetches what did, starting from
|
|
924
|
+
* the position the HOST stored last time (Gmail's `startHistoryId`, Drive's
|
|
925
|
+
* `pageToken`). Reading from the delivery's own position instead misses the
|
|
926
|
+
* very change that caused it. The package holds no state: the host stores the
|
|
927
|
+
* cursor, passes it in, and persists `cursor.next` when the run succeeds.
|
|
928
|
+
*
|
|
929
|
+
* The PHP twin is `CursorRead::read`; both read `fixtures/cursor-read/`.
|
|
930
|
+
*
|
|
931
|
+
* The decisions, each pinned by a case:
|
|
932
|
+
*
|
|
933
|
+
* - **`next` comes ONLY from the LAST page.** Gmail's `historyId` is the
|
|
934
|
+
* mailbox's CURRENT one on every page, and Google says to store it only "if
|
|
935
|
+
* you receive no nextPageToken". Taking it after page one would skip every
|
|
936
|
+
* page not yet read, silently.
|
|
937
|
+
* - **Too many pages is refused** (`cursor-overflow`), never a partial read
|
|
938
|
+
* with a cursor that skips the rest. The host's answer is a bounded resync.
|
|
939
|
+
* - **The provider's own "cursor out of range"** (`expiredStatus`, Gmail's
|
|
940
|
+
* 404) is `cursor-expired`; every OTHER failure is rethrown unchanged, so a
|
|
941
|
+
* 500 is never mistaken for a lapse.
|
|
942
|
+
* - **No stored cursor is `cursor-missing`**, and the provider is not called:
|
|
943
|
+
* a read with no starting point is a read from the beginning of time.
|
|
944
|
+
* - `collect` absent is `[]` (Gmail omits `history` when nothing changed); not
|
|
945
|
+
* a list is `bad-page`. The cursor and `next` are strings: history ids are
|
|
946
|
+
* uint64.
|
|
947
|
+
*/
|
|
948
|
+
declare const CURSOR_READ_REASONS: readonly ["cursor-missing", "cursor-expired", "cursor-overflow", "bad-page"];
|
|
949
|
+
type CursorReadReason = (typeof CURSOR_READ_REASONS)[number];
|
|
950
|
+
type CursorReadSpec = {
|
|
951
|
+
/** The read's parameter the stored cursor fills (Gmail: `startHistoryId`). */
|
|
952
|
+
param: string;
|
|
953
|
+
/** Where the NEXT cursor is read in the last page's data (Gmail: `historyId`). */
|
|
954
|
+
advanceFrom: string;
|
|
955
|
+
/** Paging, when the read pages (Gmail: `pageToken` / `nextPageToken`, `history`). */
|
|
956
|
+
page?: {
|
|
957
|
+
param: string;
|
|
958
|
+
from: string;
|
|
959
|
+
collect: string;
|
|
960
|
+
maxPages: number;
|
|
961
|
+
};
|
|
962
|
+
/** The status the provider answers for a cursor out of range (Gmail: 404). */
|
|
963
|
+
expiredStatus?: number;
|
|
964
|
+
};
|
|
965
|
+
type CursorReadResult = {
|
|
966
|
+
data: unknown;
|
|
967
|
+
cursor: {
|
|
968
|
+
used: string;
|
|
969
|
+
next: string | null;
|
|
970
|
+
};
|
|
971
|
+
};
|
|
972
|
+
/** Refused BY NAME; `reason` is the same string PHP's exception carries. */
|
|
973
|
+
declare class CursorReadError extends Error {
|
|
974
|
+
readonly reason: CursorReadReason;
|
|
975
|
+
/** The host's bounded resync, when the caller declared one (Gmail: `newer_than:7d`). */
|
|
976
|
+
readonly resyncQuery?: string | undefined;
|
|
977
|
+
constructor(reason: CursorReadReason, message: string,
|
|
978
|
+
/** The host's bounded resync, when the caller declared one (Gmail: `newer_than:7d`). */
|
|
979
|
+
resyncQuery?: string | undefined);
|
|
980
|
+
}
|
|
981
|
+
declare function readWithCursor(spec: CursorReadSpec, cursor: unknown, call: (params: Record<string, string>) => Promise<unknown>, options?: {
|
|
982
|
+
resyncQuery?: string;
|
|
983
|
+
}): Promise<CursorReadResult>;
|
|
984
|
+
|
|
919
985
|
/**
|
|
920
986
|
* API drift — being told the provider changed, rather than discovering it.
|
|
921
987
|
*
|
|
@@ -2946,4 +3012,4 @@ oidc?: OidcExpectation): Promise<WebhookVerification>;
|
|
|
2946
3012
|
*/
|
|
2947
3013
|
declare function triggerEvent(trigger: TriggerDescriptor, connection: ResolvedConnection, injected: unknown, config: Record<string, unknown>): unknown;
|
|
2948
3014
|
|
|
2949
|
-
export { AMBIGUOUS_REFUSAL, type ApiContract, type Attempt, type Attendee, 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, DELIVERY_DECODE_KINDS, type DeliveryDeclaration, type DeliveryDecode, type DeliveryMechanism, type DeliveryOutcome, type DeliveryRoute, type DriftFinding, type DriftReport, EXPIRES_AT_UNITS, type ExpiresAtUnit, FAKE_EPOCH, FORM_FIELD_JSON_REASONS, type FailureKind, type FakeRequest, type FakeValues, FormFieldJsonError, type FormFieldJsonReason, type HmacScheme, type HmacVerificationSpec, type HostEnvironment, type IdempotencyOptions, type InboundDelivery, type Invite, type InviteMethod, JWT_ALGORITHMS, type JoinTarget, type JoinTargetKind, type Jwk, type JwtVerification, 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, OIDC_JWT_SCHEME_KIND, type OidcExpectation, type OidcJwtScheme, type OidcJwtVerificationSpec, PROBLEM_SEVERITIES, PUBSUB_PUSH_REASONS, type PreparedRequest, type ProbeOutcome, type ProbeReport, type ProbeResult, type ProbeSpec, type Problem, type ProviderAdapter, PubSubPushError, type PubSubPushMessage, type PubSubPushReason, RENDERER_VERSION, REVIEW_STALE_DAYS, type RecordedShape, type RecurrenceRule, type RenderRules, type RenderedPayload, type RequestedMode, type ResolveOptions, type ResolvedConnection, type RetryPolicy, type RunIdentity, SANDBOX_KINDS, SIGNED_URI_RULES, SUPPORTED_CONNECTOR_API, type SandboxKind, type Segment, type ServiceDescriptor, type SetupStep, type ShapeMismatch, type SharedTokenScheme, type SharedTokenVerificationSpec, type SignedRequestLine, type SignedUriRule, type SpecSource, type SubscriptionLease, type TextUnit, type Transport, type TransportResponse, type TriggerDescriptor, type VerifyJwtOptions, type VerifyResult, type WebhookVerification, type WebhookVerificationSpec, assertConnectorApi, byteRangeOf, callConnector, capabilityProblems, checkAgainstOpenApi, checkAgainstRecordedShape, classifyError, classifyHttp, classifyStatus, classifyThrown, compareShape, connectionsFor, constantTimeEquals, decodeDelivery, decodeFormFieldJson, decodePubSubPush, deliver, fakeRequest, fakeValues, getConnectionHost, graphemes, handshakeResponse, header, hmac, httpFailure, idempotencyKeyFor, isEmptyPayload, isOidcJwtScheme, isOidcJwtSpec, isRemote, isSharedTokenScheme, isSharedTokenSpec, isUnconditionallyRetryable, joinTargets, leaseAction, leaseFromResponse, leaseRenewAt, leaseState, linkRanges, measure, nextOccurrence, normaliseSignedUri, parseInvite, 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, verifyJwt, verifyOidcDelivery, verifySharedToken, withResolvedLimit };
|
|
3015
|
+
export { AMBIGUOUS_REFUSAL, type ApiContract, type Attempt, type Attendee, type ByteRange, CANONICAL_METRICS, CONNECTOR_API_VERSION, CONNECTOR_MODES, CREDENTIAL_SCOPES, CURSOR_READ_REASONS, 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, CursorReadError, type CursorReadReason, type CursorReadResult, type CursorReadSpec, DEFAULT_IDEMPOTENCY_WINDOW_SECONDS, DEFAULT_RETRY, DELIVERY_DECODE_KINDS, type DeliveryDeclaration, type DeliveryDecode, type DeliveryMechanism, type DeliveryOutcome, type DeliveryRoute, type DriftFinding, type DriftReport, EXPIRES_AT_UNITS, type ExpiresAtUnit, FAKE_EPOCH, FORM_FIELD_JSON_REASONS, type FailureKind, type FakeRequest, type FakeValues, FormFieldJsonError, type FormFieldJsonReason, type HmacScheme, type HmacVerificationSpec, type HostEnvironment, type IdempotencyOptions, type InboundDelivery, type Invite, type InviteMethod, JWT_ALGORITHMS, type JoinTarget, type JoinTargetKind, type Jwk, type JwtVerification, 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, OIDC_JWT_SCHEME_KIND, type OidcExpectation, type OidcJwtScheme, type OidcJwtVerificationSpec, PROBLEM_SEVERITIES, PUBSUB_PUSH_REASONS, type PreparedRequest, type ProbeOutcome, type ProbeReport, type ProbeResult, type ProbeSpec, type Problem, type ProviderAdapter, PubSubPushError, type PubSubPushMessage, type PubSubPushReason, RENDERER_VERSION, REVIEW_STALE_DAYS, type RecordedShape, type RecurrenceRule, type RenderRules, type RenderedPayload, type RequestedMode, type ResolveOptions, type ResolvedConnection, type RetryPolicy, type RunIdentity, SANDBOX_KINDS, SIGNED_URI_RULES, SUPPORTED_CONNECTOR_API, type SandboxKind, type Segment, type ServiceDescriptor, type SetupStep, type ShapeMismatch, type SharedTokenScheme, type SharedTokenVerificationSpec, type SignedRequestLine, type SignedUriRule, type SpecSource, type SubscriptionLease, type TextUnit, type Transport, type TransportResponse, type TriggerDescriptor, type VerifyJwtOptions, type VerifyResult, type WebhookVerification, type WebhookVerificationSpec, assertConnectorApi, byteRangeOf, callConnector, capabilityProblems, checkAgainstOpenApi, checkAgainstRecordedShape, classifyError, classifyHttp, classifyStatus, classifyThrown, compareShape, connectionsFor, constantTimeEquals, decodeDelivery, decodeFormFieldJson, decodePubSubPush, deliver, fakeRequest, fakeValues, getConnectionHost, graphemes, handshakeResponse, header, hmac, httpFailure, idempotencyKeyFor, isEmptyPayload, isOidcJwtScheme, isOidcJwtSpec, isRemote, isSharedTokenScheme, isSharedTokenSpec, isUnconditionallyRetryable, joinTargets, leaseAction, leaseFromResponse, leaseRenewAt, leaseState, linkRanges, measure, nextOccurrence, normaliseSignedUri, parseInvite, parseMime, payloadHash, postChain, probe, providerProblems, providerSandboxIsSelectable, readWithCursor, 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, verifyJwt, verifyOidcDelivery, verifySharedToken, withResolvedLimit };
|
package/dist/index.js
CHANGED
|
@@ -163,10 +163,10 @@ var lastCallAt = /* @__PURE__ */ new Map();
|
|
|
163
163
|
async function respectRate(channel, minIntervalMs, now = () => Date.now(), sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
|
|
164
164
|
if (minIntervalMs <= 0) return { waitedMs: 0 };
|
|
165
165
|
const previous = lastCallAt.get(channel);
|
|
166
|
-
const
|
|
167
|
-
const waitedMs = previous === void 0 ? 0 : Math.max(0, previous + minIntervalMs -
|
|
166
|
+
const at2 = now();
|
|
167
|
+
const waitedMs = previous === void 0 ? 0 : Math.max(0, previous + minIntervalMs - at2);
|
|
168
168
|
if (waitedMs > 0) await sleep(waitedMs);
|
|
169
|
-
lastCallAt.set(channel,
|
|
169
|
+
lastCallAt.set(channel, at2 + waitedMs);
|
|
170
170
|
return { waitedMs };
|
|
171
171
|
}
|
|
172
172
|
function resetRateState() {
|
|
@@ -664,6 +664,71 @@ function readString(config, key) {
|
|
|
664
664
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : null;
|
|
665
665
|
}
|
|
666
666
|
|
|
667
|
+
// src/cursor-read.ts
|
|
668
|
+
var CURSOR_READ_REASONS = ["cursor-missing", "cursor-expired", "cursor-overflow", "bad-page"];
|
|
669
|
+
var CursorReadError = class extends Error {
|
|
670
|
+
constructor(reason, message, resyncQuery) {
|
|
671
|
+
super(message);
|
|
672
|
+
this.reason = reason;
|
|
673
|
+
this.resyncQuery = resyncQuery;
|
|
674
|
+
this.name = "CursorReadError";
|
|
675
|
+
}
|
|
676
|
+
reason;
|
|
677
|
+
resyncQuery;
|
|
678
|
+
};
|
|
679
|
+
async function readWithCursor(spec, cursor, call, options = {}) {
|
|
680
|
+
const refuse = (reason, message) => new CursorReadError(reason, message, options.resyncQuery);
|
|
681
|
+
const used = asCursor(cursor);
|
|
682
|
+
if (used === null) throw refuse("cursor-missing", `no stored ${spec.param}: the host seeds one before the first read`);
|
|
683
|
+
const collected = [];
|
|
684
|
+
let last;
|
|
685
|
+
let token = null;
|
|
686
|
+
let pages = 0;
|
|
687
|
+
for (; ; ) {
|
|
688
|
+
if (spec.page && pages === spec.page.maxPages) {
|
|
689
|
+
throw refuse("cursor-overflow", `more than ${spec.page.maxPages} pages since ${spec.param} ${used}`);
|
|
690
|
+
}
|
|
691
|
+
const params = { [spec.param]: used };
|
|
692
|
+
if (spec.page && token !== null) params[spec.page.param] = token;
|
|
693
|
+
try {
|
|
694
|
+
last = await call(params);
|
|
695
|
+
} catch (error) {
|
|
696
|
+
const status = error?.status;
|
|
697
|
+
if (spec.expiredStatus !== void 0 && status === spec.expiredStatus) {
|
|
698
|
+
throw refuse("cursor-expired", `${spec.param} ${used} is out of the provider's range (${status})`);
|
|
699
|
+
}
|
|
700
|
+
throw error;
|
|
701
|
+
}
|
|
702
|
+
pages++;
|
|
703
|
+
if (!spec.page) break;
|
|
704
|
+
const items = at(last, spec.page.collect);
|
|
705
|
+
if (items !== void 0 && !Array.isArray(items)) {
|
|
706
|
+
throw refuse("bad-page", `${spec.page.collect} is not a list`);
|
|
707
|
+
}
|
|
708
|
+
if (items) collected.push(...items);
|
|
709
|
+
token = asCursor(at(last, spec.page.from));
|
|
710
|
+
if (token === null) break;
|
|
711
|
+
}
|
|
712
|
+
const data = spec.page ? withList(last, spec.page.collect, collected) : last;
|
|
713
|
+
return { data, cursor: { used, next: asCursor(at(last, spec.advanceFrom)) } };
|
|
714
|
+
}
|
|
715
|
+
function asCursor(value) {
|
|
716
|
+
if (typeof value === "string") return value === "" ? null : value;
|
|
717
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
function at(value, path) {
|
|
721
|
+
return path.split(".").reduce(
|
|
722
|
+
(v, key) => v !== null && typeof v === "object" && !Array.isArray(v) ? v[key] : void 0,
|
|
723
|
+
value
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
function withList(data, path, list) {
|
|
727
|
+
const [head, ...rest] = path.split(".");
|
|
728
|
+
const base = data !== null && typeof data === "object" && !Array.isArray(data) ? data : {};
|
|
729
|
+
return { ...base, [head]: rest.length ? withList(base[head], rest.join("."), list) : list };
|
|
730
|
+
}
|
|
731
|
+
|
|
667
732
|
// src/drift.ts
|
|
668
733
|
function resolveRef(document, node, depth = 0) {
|
|
669
734
|
if (depth > 8 || node === null || typeof node !== "object") return node;
|
|
@@ -1318,32 +1383,32 @@ function base64urlBytes(segment) {
|
|
|
1318
1383
|
var EXPIRES_AT_UNITS = ["rfc3339", "epoch-ms"];
|
|
1319
1384
|
var INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
1320
1385
|
var DEFAULT_CONTEXT = { service: "", operation: "subscription" };
|
|
1321
|
-
function instantMs(value, field,
|
|
1386
|
+
function instantMs(value, field, at2) {
|
|
1322
1387
|
if (typeof value !== "string" || !INSTANT.test(value)) {
|
|
1323
1388
|
throw new ConnectorConfigError(
|
|
1324
1389
|
`${field} must be an RFC 3339 instant such as "2026-09-22T00:00:00Z", got ${JSON.stringify(value)}. A provider's own shape \u2014 Google's epoch milliseconds, say \u2014 is converted by the connector, never guessed at here.`,
|
|
1325
|
-
|
|
1390
|
+
at2
|
|
1326
1391
|
);
|
|
1327
1392
|
}
|
|
1328
1393
|
const ms = Date.parse(value.replace(/(\.\d{3})\d+/, "$1"));
|
|
1329
1394
|
if (Number.isNaN(ms)) {
|
|
1330
|
-
throw new ConnectorConfigError(`${field} is not a real instant: ${JSON.stringify(value)}`,
|
|
1395
|
+
throw new ConnectorConfigError(`${field} is not a real instant: ${JSON.stringify(value)}`, at2);
|
|
1331
1396
|
}
|
|
1332
1397
|
return ms;
|
|
1333
1398
|
}
|
|
1334
|
-
function leaseFromResponse(declaration, response,
|
|
1399
|
+
function leaseFromResponse(declaration, response, at2 = DEFAULT_CONTEXT) {
|
|
1335
1400
|
const { expiresAtFrom: path, expiresAtUnit: unit } = declaration;
|
|
1336
1401
|
if (!EXPIRES_AT_UNITS.includes(unit)) {
|
|
1337
1402
|
throw new ConnectorConfigError(
|
|
1338
1403
|
`expiresAtUnit must be one of ${EXPIRES_AT_UNITS.join(" | ")}, got ${JSON.stringify(unit)}.`,
|
|
1339
|
-
|
|
1404
|
+
at2
|
|
1340
1405
|
);
|
|
1341
1406
|
}
|
|
1342
1407
|
const value = readPath(response, path);
|
|
1343
1408
|
if (value === void 0 || value === null) {
|
|
1344
1409
|
throw new ConnectorConfigError(
|
|
1345
1410
|
`${path} is not present in the response, so no lease can be built \u2014 a subscription with no known expiry is one nobody renews.`,
|
|
1346
|
-
|
|
1411
|
+
at2
|
|
1347
1412
|
);
|
|
1348
1413
|
}
|
|
1349
1414
|
let expiresAt;
|
|
@@ -1352,7 +1417,7 @@ function leaseFromResponse(declaration, response, at = DEFAULT_CONTEXT) {
|
|
|
1352
1417
|
if (!Number.isSafeInteger(ms)) {
|
|
1353
1418
|
throw new ConnectorConfigError(
|
|
1354
1419
|
`${path} must be epoch milliseconds as digits under "epoch-ms", got ${JSON.stringify(value)}.`,
|
|
1355
|
-
|
|
1420
|
+
at2
|
|
1356
1421
|
);
|
|
1357
1422
|
}
|
|
1358
1423
|
expiresAt = new Date(ms).toISOString();
|
|
@@ -1360,14 +1425,14 @@ function leaseFromResponse(declaration, response, at = DEFAULT_CONTEXT) {
|
|
|
1360
1425
|
if (typeof value !== "string" || !INSTANT.test(value)) {
|
|
1361
1426
|
throw new ConnectorConfigError(
|
|
1362
1427
|
`${path} must be an RFC 3339 instant under "rfc3339", got ${JSON.stringify(value)}.`,
|
|
1363
|
-
|
|
1428
|
+
at2
|
|
1364
1429
|
);
|
|
1365
1430
|
}
|
|
1366
|
-
expiresAt = new Date(instantMs(value, path,
|
|
1431
|
+
expiresAt = new Date(instantMs(value, path, at2)).toISOString();
|
|
1367
1432
|
}
|
|
1368
1433
|
return subscriptionLease(
|
|
1369
1434
|
{ expiresAt, renewBeforeSeconds: declaration.renewBeforeSeconds, renewOperation: declaration.renewOperation },
|
|
1370
|
-
|
|
1435
|
+
at2
|
|
1371
1436
|
);
|
|
1372
1437
|
}
|
|
1373
1438
|
function readPath(value, path) {
|
|
@@ -1378,18 +1443,18 @@ function readPath(value, path) {
|
|
|
1378
1443
|
}
|
|
1379
1444
|
return current;
|
|
1380
1445
|
}
|
|
1381
|
-
function subscriptionLease(input,
|
|
1382
|
-
instantMs(input.expiresAt, "expiresAt",
|
|
1446
|
+
function subscriptionLease(input, at2 = DEFAULT_CONTEXT) {
|
|
1447
|
+
instantMs(input.expiresAt, "expiresAt", at2);
|
|
1383
1448
|
if (!Number.isInteger(input.renewBeforeSeconds) || input.renewBeforeSeconds <= 0) {
|
|
1384
1449
|
throw new ConnectorConfigError(
|
|
1385
1450
|
`renewBeforeSeconds must be a positive whole number of seconds, got ${JSON.stringify(input.renewBeforeSeconds)}. Zero would make the lease due only at the instant it expires, which is a lease nobody renews.`,
|
|
1386
|
-
|
|
1451
|
+
at2
|
|
1387
1452
|
);
|
|
1388
1453
|
}
|
|
1389
1454
|
if (typeof input.renewOperation !== "string" || input.renewOperation.trim() === "") {
|
|
1390
1455
|
throw new ConnectorConfigError(
|
|
1391
1456
|
"renewOperation must name the operation the host calls when the lease is due; a due lease with nothing to call is one nobody renews.",
|
|
1392
|
-
|
|
1457
|
+
at2
|
|
1393
1458
|
);
|
|
1394
1459
|
}
|
|
1395
1460
|
return { expiresAt: input.expiresAt, renewBeforeSeconds: input.renewBeforeSeconds, renewOperation: input.renewOperation };
|
|
@@ -1398,10 +1463,10 @@ function leaseRenewAt(lease) {
|
|
|
1398
1463
|
return new Date(instantMs(lease.expiresAt, "expiresAt", DEFAULT_CONTEXT) - lease.renewBeforeSeconds * 1e3).toISOString();
|
|
1399
1464
|
}
|
|
1400
1465
|
function leaseState(lease, now) {
|
|
1401
|
-
const
|
|
1466
|
+
const at2 = now instanceof Date ? now.getTime() : instantMs(now, "now", DEFAULT_CONTEXT);
|
|
1402
1467
|
const expires = instantMs(lease.expiresAt, "expiresAt", DEFAULT_CONTEXT);
|
|
1403
|
-
if (
|
|
1404
|
-
if (
|
|
1468
|
+
if (at2 >= expires) return "expired";
|
|
1469
|
+
if (at2 >= expires - lease.renewBeforeSeconds * 1e3) return "due";
|
|
1405
1470
|
return "active";
|
|
1406
1471
|
}
|
|
1407
1472
|
function leaseAction(lease, now) {
|
|
@@ -1721,8 +1786,8 @@ function splitMultipart(body, boundary) {
|
|
|
1721
1786
|
if (partStart >= 0 && partStart <= body.length) children.push(body.subarray(partStart));
|
|
1722
1787
|
return children;
|
|
1723
1788
|
}
|
|
1724
|
-
function startsWith(haystack,
|
|
1725
|
-
for (let k = 0; k < needle.length; k++) if (haystack[
|
|
1789
|
+
function startsWith(haystack, at2, needle) {
|
|
1790
|
+
for (let k = 0; k < needle.length; k++) if (haystack[at2 + k] !== needle[k]) return false;
|
|
1726
1791
|
return true;
|
|
1727
1792
|
}
|
|
1728
1793
|
function parseMime(raw) {
|
|
@@ -2363,6 +2428,7 @@ export {
|
|
|
2363
2428
|
CONNECTOR_API_VERSION,
|
|
2364
2429
|
CONNECTOR_MODES,
|
|
2365
2430
|
CREDENTIAL_SCOPES,
|
|
2431
|
+
CURSOR_READ_REASONS,
|
|
2366
2432
|
ConnectorAmbiguous,
|
|
2367
2433
|
ConnectorApiMismatch,
|
|
2368
2434
|
ConnectorAuthError,
|
|
@@ -2374,6 +2440,7 @@ export {
|
|
|
2374
2440
|
ConnectorRequestError,
|
|
2375
2441
|
ConnectorTransient,
|
|
2376
2442
|
ConnectorUnreachable,
|
|
2443
|
+
CursorReadError,
|
|
2377
2444
|
DEFAULT_IDEMPOTENCY_WINDOW_SECONDS,
|
|
2378
2445
|
DEFAULT_RETRY,
|
|
2379
2446
|
DELIVERY_DECODE_KINDS,
|
|
@@ -2442,6 +2509,7 @@ export {
|
|
|
2442
2509
|
probe,
|
|
2443
2510
|
providerProblems,
|
|
2444
2511
|
providerSandboxIsSelectable,
|
|
2512
|
+
readWithCursor,
|
|
2445
2513
|
registerConnectionHost,
|
|
2446
2514
|
registerTransport,
|
|
2447
2515
|
render,
|