@repost/client 0.2.0 → 0.4.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.
Files changed (75) hide show
  1. package/README.md +15 -85
  2. package/dist/cjs/index-e0zw7VDH.cjs +2987 -0
  3. package/dist/cjs/index-e0zw7VDH.cjs.map +1 -0
  4. package/dist/cjs/index.cjs +23 -1046
  5. package/dist/cjs/index.cjs.map +1 -1
  6. package/dist/cjs/node-Dd92VNS7.cjs +841 -0
  7. package/dist/cjs/node-Dd92VNS7.cjs.map +1 -0
  8. package/dist/cjs/observer-dykSFHYi.cjs +69 -0
  9. package/dist/cjs/observer-dykSFHYi.cjs.map +1 -0
  10. package/dist/cjs/otel/index.cjs +99 -0
  11. package/dist/cjs/otel/index.cjs.map +1 -0
  12. package/dist/cjs/testing/index.cjs +257 -0
  13. package/dist/cjs/testing/index.cjs.map +1 -0
  14. package/dist/cjs/types/config.d.ts +28 -0
  15. package/dist/cjs/types/errors.d.ts +83 -0
  16. package/dist/cjs/types/index.d.ts +8 -3
  17. package/dist/cjs/types/observer.d.ts +44 -0
  18. package/dist/cjs/types/operation-events.d.ts +8 -0
  19. package/dist/cjs/types/operation-input.d.ts +5 -0
  20. package/dist/cjs/types/operation-policy.d.ts +23 -0
  21. package/dist/cjs/types/operation.d.ts +14 -0
  22. package/dist/cjs/types/otel/index.d.ts +2 -0
  23. package/dist/cjs/types/otel/metrics.d.ts +5 -0
  24. package/dist/cjs/types/otel/telemetry.d.ts +5 -0
  25. package/dist/cjs/types/runtime-state.d.ts +45 -0
  26. package/dist/cjs/types/serialize.d.ts +9 -3
  27. package/dist/cjs/types/telemetry.d.ts +43 -0
  28. package/dist/cjs/types/testing/deterministic.d.ts +19 -0
  29. package/dist/cjs/types/testing/index.d.ts +16 -0
  30. package/dist/cjs/types/testing/manual-clock.d.ts +12 -0
  31. package/dist/cjs/types/testing/recording-observer.d.ts +11 -0
  32. package/dist/cjs/types/testing/stub-transport.d.ts +35 -0
  33. package/dist/cjs/types/transport/connect-proxy.d.ts +30 -0
  34. package/dist/cjs/types/transport/failure.d.ts +7 -0
  35. package/dist/cjs/types/transport/framing.d.ts +8 -0
  36. package/dist/cjs/types/transport/h2.d.ts +3 -0
  37. package/dist/cjs/types/transport/node.d.ts +3 -0
  38. package/dist/cjs/types/transport/response-reader.d.ts +6 -0
  39. package/dist/cjs/types/transport/strict-json.d.ts +5 -0
  40. package/dist/cjs/types/transport/tls.d.ts +14 -0
  41. package/dist/cjs/types/transport/undici-compat.d.ts +47 -0
  42. package/dist/cjs/types/transport.d.ts +42 -19
  43. package/dist/cjs/types/types.d.ts +146 -23
  44. package/dist/cjs/types/version.d.ts +2 -0
  45. package/dist/cjs/types/webhooks.d.ts +15 -0
  46. package/dist/cjs/version-CGqSWJir.cjs +7 -0
  47. package/dist/cjs/version-CGqSWJir.cjs.map +1 -0
  48. package/dist/esm/index-DRD5FBax.mjs +2967 -0
  49. package/dist/esm/index-DRD5FBax.mjs.map +1 -0
  50. package/dist/esm/index.mjs +3 -1041
  51. package/dist/esm/index.mjs.map +1 -1
  52. package/dist/esm/node-BAJt_qhB.mjs +839 -0
  53. package/dist/esm/node-BAJt_qhB.mjs.map +1 -0
  54. package/dist/esm/observer-Dns2X4wE.mjs +66 -0
  55. package/dist/esm/observer-Dns2X4wE.mjs.map +1 -0
  56. package/dist/esm/otel/index.mjs +96 -0
  57. package/dist/esm/otel/index.mjs.map +1 -0
  58. package/dist/esm/testing/index.mjs +248 -0
  59. package/dist/esm/testing/index.mjs.map +1 -0
  60. package/dist/esm/version-Dp5vd2nu.mjs +5 -0
  61. package/dist/esm/version-Dp5vd2nu.mjs.map +1 -0
  62. package/index.d.ts +1 -1
  63. package/index.js +3 -4
  64. package/index.mjs +1 -1
  65. package/otel/index.d.ts +1 -0
  66. package/otel/index.js +3 -0
  67. package/otel/index.mjs +1 -0
  68. package/package.json +38 -9
  69. package/runtime/index.d.ts +1 -1
  70. package/runtime/index.js +2 -2
  71. package/runtime/index.mjs +1 -1
  72. package/scripts/postinstall.js +2 -2
  73. package/testing/index.d.ts +1 -0
  74. package/testing/index.js +3 -0
  75. package/testing/index.mjs +1 -0
@@ -0,0 +1,47 @@
1
+ import { type ProxyOptions } from "./connect-proxy";
2
+ export interface UndiciPoolOptions {
3
+ readonly connections: number;
4
+ readonly clientTtl: number;
5
+ readonly keepAliveTimeout: number;
6
+ readonly allowH2: boolean;
7
+ readonly connectTimeout: number;
8
+ readonly tls?: {
9
+ readonly caCertificates?: readonly string[];
10
+ readonly minVersion?: "TLSv1.2" | "TLSv1.3";
11
+ readonly maxVersion?: "TLSv1.2" | "TLSv1.3";
12
+ readonly ciphers?: readonly string[];
13
+ readonly clientCertificate?: {
14
+ readonly certificate: string;
15
+ readonly key: string;
16
+ readonly passphrase?: string;
17
+ };
18
+ };
19
+ readonly dnsResolver?: (host: string) => Promise<{
20
+ address: string;
21
+ family: 4 | 6;
22
+ }[]>;
23
+ readonly proxy?: ProxyOptions;
24
+ }
25
+ export interface UndiciDispatchRequest {
26
+ readonly path: string;
27
+ readonly headers: string[];
28
+ readonly body: Uint8Array;
29
+ readonly headersTimeout: number;
30
+ readonly bodyTimeout: number;
31
+ readonly signal: AbortSignal;
32
+ readonly onBodySent: () => void;
33
+ readonly maxResponseBytes: number;
34
+ }
35
+ export interface UndiciDispatchResponse {
36
+ readonly status: number;
37
+ readonly rawHeaders: readonly Uint8Array[];
38
+ readonly chunks: readonly Uint8Array[];
39
+ readonly compressedBytes: number;
40
+ readonly truncated: boolean;
41
+ }
42
+ export interface UndiciPool {
43
+ dispatch(request: UndiciDispatchRequest): Promise<UndiciDispatchResponse>;
44
+ close(): Promise<void>;
45
+ }
46
+ /** The sole Undici compatibility boundary for the SDK. */
47
+ export declare function createUndiciPool(origin: string, options: UndiciPoolOptions): UndiciPool;
@@ -1,28 +1,51 @@
1
1
  import type { Transport } from "./types";
2
- /** A publish rejected or failed by the Repost API. */
3
- export declare class RepostPublishError extends Error {
4
- readonly status?: number;
5
- readonly body?: unknown;
6
- constructor(message: string, status?: number, body?: unknown);
7
- }
2
+ export { RepostPublishError } from "./errors";
8
3
  export interface HttpTransportOptions {
9
- /** Injectable fetch, for tests and custom agents. Defaults to global fetch. */
4
+ /** Portable fetch implementation. Defaults to `globalThis.fetch` at attempt time. */
10
5
  fetch?: typeof fetch;
11
- /** Retries after the initial attempt. Default 3. */
6
+ /** @deprecated Runtime retries are configured with `RepostClientOptions.maxAttempts`. */
12
7
  maxRetries?: number;
13
- /** Base backoff delay. Default 250ms, doubled per attempt with jitter. */
8
+ /** @deprecated Runtime backoff is configured with `RepostClientOptions.retryBaseDelayMs`. */
14
9
  baseDelayMs?: number;
15
- /** Per-attempt timeout (each retry gets a fresh budget). Default 30s. */
10
+ /** @deprecated Use `RepostClientOptions.attemptTimeoutMs`. */
16
11
  timeoutMs?: number;
12
+ tls?: {
13
+ caCertificates?: readonly string[];
14
+ minVersion?: "TLSv1.2" | "TLSv1.3";
15
+ maxVersion?: "TLSv1.2" | "TLSv1.3";
16
+ ciphers?: readonly string[];
17
+ clientCertificate?: {
18
+ certificate: string;
19
+ key: string;
20
+ passphrase?: string;
21
+ };
22
+ };
23
+ proxy?: {
24
+ url: string;
25
+ credentialsProvider?: () => {
26
+ username: string;
27
+ password: string;
28
+ } | Promise<{
29
+ username: string;
30
+ password: string;
31
+ }>;
32
+ };
33
+ dnsResolver?: (host: string) => Promise<{
34
+ address: string;
35
+ family: 4 | 6;
36
+ }[]>;
37
+ http2?: boolean;
38
+ maxConnectionsPerOrigin?: number;
39
+ connectionLifetimeMs?: number;
40
+ connectionIdleTimeoutMs?: number;
17
41
  }
18
- /**
19
- * The HTTP transport against Repost's publish API (workstream A).
20
- *
21
- * One idempotency key is minted per send() and reused across internal
22
- * retries, so retrying is always safe: the server deduplicates. Retryable
23
- * outcomes are network errors, 5xx, 429, and 409 (a concurrent duplicate
24
- * still in flight); Retry-After is honored when present.
25
- */
42
+ /** Portable one-attempt fetch transport. Retry and deadlines belong to the runtime. */
26
43
  export declare function createHttpTransport(options?: HttpTransportOptions): Transport;
27
- /** The default transport: real HTTP against the publish API. */
44
+ /** Explicit portable transport for edge/worker runtimes. */
45
+ export declare const createFetchTransport: typeof createHttpTransport;
46
+ /** Selects the production Node lane; the package supports Node 20 and newer. */
47
+ export declare function resolveDefaultTransport(options?: HttpTransportOptions): Transport;
48
+ /** Production Node transport, loaded on first use so fetch-only bundles omit Undici. */
49
+ export declare function createNodeTransport(options?: HttpTransportOptions): Transport;
50
+ /** @deprecated Prefer the runtime-selected transport. */
28
51
  export declare const httpTransport: Transport;
@@ -1,15 +1,17 @@
1
1
  /**
2
2
  * Options for `createRepostClient` (the factory the generated client exports).
3
- * Construction is lazy: nothing is validated until a send.
3
+ * Construction snapshots and validates configuration before any send.
4
4
  */
5
5
  export interface RepostClientOptions {
6
6
  /**
7
7
  * The environment's publish API key (created with the environment in the
8
8
  * dashboard). Defaults to `process.env.REPOST_SEND_API_KEY` — the variable
9
- * `repost schema init` scaffolds into `.env` — read at send time. A send
9
+ * `repost schema init` scaffolds into `.env` — read at construction time. A send
10
10
  * without a key throws.
11
11
  */
12
12
  apiKey?: string;
13
+ /** Resolve a credential once per admitted operation. Mutually exclusive with `apiKey`. */
14
+ apiKeyProvider?: () => string | Promise<string>;
13
15
  /**
14
16
  * @deprecated Use `apiKey` (or `REPOST_SEND_API_KEY`). Still honored when
15
17
  * `apiKey` is absent, checked before the environment variables.
@@ -17,7 +19,7 @@ export interface RepostClientOptions {
17
19
  token?: string;
18
20
  /**
19
21
  * API base URL. Defaults to `process.env.REPOST_API_URL` (the existing
20
- * Repost CLI convention), read at send time.
22
+ * Repost CLI convention), read at construction time.
21
23
  */
22
24
  apiUrl?: string;
23
25
  /**
@@ -26,6 +28,46 @@ export interface RepostClientOptions {
26
28
  * tests.
27
29
  */
28
30
  transport?: Transport;
31
+ /**
32
+ * Injectable clock and id generators, used by the envelope timestamp and
33
+ * `@default(now()/uuid()/cuid())` injection. Defaults to the real ones —
34
+ * override for deterministic tests (the conformance suite's requirement:
35
+ * every runtime must expose these seams).
36
+ */
37
+ generators?: Generators;
38
+ attemptTimeoutMs?: number;
39
+ operationTimeoutMs?: number;
40
+ connectTimeoutMs?: number;
41
+ maxAttempts?: number;
42
+ retryBaseDelayMs?: number;
43
+ retryMaxDelayMs?: number;
44
+ maxInFlightOperations?: number;
45
+ maxBufferedBytes?: number;
46
+ /** Set to false only when sends without a caller key must fail closed. */
47
+ idempotencyKeyGenerator?: (() => string) | false;
48
+ retryEntropy?: RetryEntropy;
49
+ monotonicClock?: () => number;
50
+ wallClock?: () => number;
51
+ scheduler?: Scheduler;
52
+ observer?: import("./observer").RepostObserver;
53
+ telemetry?: import("./telemetry").RepostTelemetry;
54
+ userAgentSuffix?: string;
55
+ httpTransportOptions?: import("./transport").HttpTransportOptions;
56
+ }
57
+ export interface RetryEntropy {
58
+ nextInt(exclusiveBound: number): number;
59
+ }
60
+ export interface Scheduler {
61
+ sleep(ms: number, signal?: AbortSignal): Promise<void>;
62
+ }
63
+ /** Injectable clock and id generators (deterministic-test seam). */
64
+ export interface Generators {
65
+ /** ISO-8601 timestamp source. Defaults to `new Date().toISOString()`. */
66
+ now?: () => string;
67
+ /** UUID source for `@default(uuid())`. Defaults to `crypto.randomUUID()`. */
68
+ uuid?: () => string;
69
+ /** cuid2 source for `@default(cuid())`. Defaults to `@paralleldrive/cuid2`. */
70
+ cuid?: () => string;
29
71
  }
30
72
  /** The Standard Webhooks envelope the runtime constructs and signs-for-send. */
31
73
  export interface Envelope {
@@ -36,20 +78,58 @@ export interface Envelope {
36
78
  /** The serialized payload (wire names, defaults injected). */
37
79
  data: Record<string, unknown>;
38
80
  }
39
- /** Everything a transport needs to deliver one webhook publish. */
40
- export interface SendRequest {
41
- token: string;
42
- apiUrl: string | undefined;
43
- /** The receiving tenant — maps 1:1 to Svix's `app_uid` usage. */
44
- customerId: string;
45
- /**
46
- * Caller-owned idempotency key (e.g. `order-42`): the server dedups it for
47
- * 24h and rejects reuse with a different payload (422). Absent, the
48
- * transport mints one per send, deduplicating internal retries only.
49
- */
50
- idempotencyKey?: string;
51
- envelope: Envelope;
81
+ export interface CommitTracker {
82
+ readonly committed: boolean;
83
+ markCommitted(): void;
52
84
  }
85
+ export type BoundedHeaders = Readonly<Record<string, readonly string[]>>;
86
+ /** Everything a one-attempt transport needs for one runtime-owned attempt. */
87
+ export interface AttemptRequest {
88
+ readonly url: string;
89
+ readonly headers: readonly (readonly [string, string])[];
90
+ readonly bodyBytes: Uint8Array;
91
+ readonly attemptNumber: number;
92
+ readonly connectTimeoutMs: number;
93
+ readonly attemptTimeoutMs: number;
94
+ readonly signal: AbortSignal;
95
+ readonly commitTracker: CommitTracker;
96
+ }
97
+ export type AttemptOutcome = {
98
+ readonly kind: "response";
99
+ readonly status: number;
100
+ readonly headers: BoundedHeaders;
101
+ readonly bodyBytes: Uint8Array;
102
+ readonly compressedBytes: number;
103
+ readonly decompressedBytes: number;
104
+ readonly truncated: boolean;
105
+ readonly limitExceeded?: boolean;
106
+ readonly protocolError?: boolean;
107
+ readonly proxyError?: boolean;
108
+ readonly headerLimitExceeded?: boolean;
109
+ /** True when the transport already enforced compressed/decompressed byte and ratio limits. */
110
+ readonly transportLimitsApplied?: boolean;
111
+ readonly nonRetryable?: boolean;
112
+ readonly responseHeaderFields?: number;
113
+ readonly responseHeaderBytes?: number;
114
+ /** Retry-After delay sampled by the transport when response headers arrived. */
115
+ readonly retryAfterDelayMs?: number | null;
116
+ /** Release a custom response resource after the runtime has consumed it. */
117
+ readonly close?: () => void | Promise<void>;
118
+ } | {
119
+ readonly kind: "failure";
120
+ readonly code: "DNS" | "CONNECT" | "PROXY" | "TLS" | "IO" | "ATTEMPT_TIMEOUT";
121
+ readonly reason: import("./errors").RepostFailureReason | null;
122
+ readonly committed: boolean;
123
+ /** Runtime-owned sanitization metadata for a thrown transport seam. */
124
+ readonly causeCategory?: import("./errors").RepostCauseCategory;
125
+ readonly retryable?: boolean;
126
+ readonly httpStatus?: number | null;
127
+ readonly compressedBytes?: number;
128
+ readonly decompressedBytes?: number;
129
+ readonly truncated?: boolean;
130
+ readonly responseHeaderFields?: number;
131
+ readonly responseHeaderBytes?: number;
132
+ };
53
133
  /**
54
134
  * The result of a webhook send, as returned by Repost's publish API (202).
55
135
  */
@@ -63,12 +143,28 @@ export interface SendResult {
63
143
  /** The envelope's ISO-8601 timestamp. */
64
144
  timestamp: string;
65
145
  }
146
+ export interface SendOperationOutcome<T = SendResult> {
147
+ readonly operationId: string | null;
148
+ readonly code: import("./errors").RepostErrorCode | "OK";
149
+ readonly deliveryState: import("./errors").DeliveryState;
150
+ readonly attemptCount: number;
151
+ readonly httpStatus: number | null;
152
+ readonly idempotencyKey: string | null;
153
+ readonly result: T | null;
154
+ readonly error: import("./errors").RepostError | null;
155
+ }
156
+ /** A native Promise with stable cancellation and reconciliation metadata. */
157
+ export type SendOperation<T = SendResult> = Promise<T> & {
158
+ readonly outcome: Promise<SendOperationOutcome<T>>;
159
+ cancel(): void;
160
+ };
66
161
  /**
67
162
  * TRANSPORT SEAM: how a send reaches Repost. The HTTP transport against the
68
163
  * publish API is the default; the no-network stub serves tests.
69
164
  */
70
165
  export interface Transport {
71
- send(request: SendRequest): Promise<SendResult>;
166
+ send(request: AttemptRequest): Promise<AttemptOutcome>;
167
+ close?(): void | Promise<void>;
72
168
  }
73
169
  /**
74
170
  * An `@default` injection spec: literals are injected verbatim; `now()` emits
@@ -89,20 +185,38 @@ export type DefaultSpec = {
89
185
  * One field's serialization descriptor, as emitted into the generated client
90
186
  * by `repost generate`. Field order is payload key order.
91
187
  */
92
- export interface FieldDescriptor {
188
+ export type ScalarKind = "string" | "boolean" | "int64" | "float64" | "datetime" | "json" | "enum" | "model";
189
+ /** Descriptor-format-v2 field facts, emitted in this stable key order. */
190
+ export interface FieldDescriptorV2 {
93
191
  /** The DSL identifier — the property name on the SDK input. */
192
+ schemaName: string;
193
+ /** The wire name after `@map` (always explicit in descriptor v2). */
194
+ wireName: string;
195
+ /** The language-neutral scalar identity used for validation. */
196
+ scalarKind: ScalarKind;
197
+ /** Referenced enum/model descriptor ID (required for those scalar kinds). */
198
+ descriptorId?: string;
199
+ /** Whether omission is an input error. */
200
+ requiredInInput: boolean;
201
+ /** Whether an explicitly present null is legal. */
202
+ nullableInInput: boolean;
203
+ /** True for list containers; elements themselves are never nullable. */
204
+ list: boolean;
205
+ /** Typed client-side default, or null when the field has none. */
206
+ default: DefaultSpec | null;
207
+ }
208
+ /** Immutable format-1 compatibility shape used only by frozen vectors. */
209
+ export interface LegacyFieldDescriptor {
94
210
  name: string;
95
- /** The `@map`'d wire name; present only when it differs from `name`. */
96
211
  wire?: string;
97
- /** True for `Field[]` / `Field[]?` — elements are serialized one by one. */
98
212
  list?: boolean;
99
- /** A nested payload model to recurse into, by descriptor name. */
100
213
  model?: string;
101
- /** Enum member name → wire value (the possibly-`@map`'d database name). */
102
214
  enum?: Record<string, string>;
103
- /** `@default` injection when the field is absent from the input. */
104
215
  default?: DefaultSpec;
105
216
  }
217
+ export type FieldDescriptor = FieldDescriptorV2 | LegacyFieldDescriptor;
218
+ /** Enum descriptor ID → member name → wire value. */
219
+ export type EnumDescriptors = Record<string, Record<string, string>>;
106
220
  /** A payload model's serialization descriptor. */
107
221
  export interface ModelDescriptor {
108
222
  fields: FieldDescriptor[];
@@ -118,6 +232,15 @@ export interface EventDescriptor {
118
232
  export type WebhookDescriptors = Record<string, Record<string, EventDescriptor>>;
119
233
  /** Everything the runtime needs from the generated client. */
120
234
  export interface SchemaDescriptor {
235
+ /**
236
+ * The descriptor-format version the generated client was emitted for.
237
+ * `buildWebhooks` refuses a mismatch at construction. Absent only in
238
+ * packages generated before versioning (accepted with a warning for one
239
+ * release).
240
+ */
241
+ descriptorFormatVersion?: number;
242
+ /** Enum descriptor ID → member wire mapping. */
243
+ enums: EnumDescriptors;
121
244
  models: Record<string, ModelDescriptor>;
122
245
  webhooks: WebhookDescriptors;
123
246
  }
@@ -0,0 +1,2 @@
1
+ /** Package version embedded in runtime identifiers and telemetry instruments. */
2
+ export declare const PACKAGE_VERSION = "0.4.0";
@@ -1,4 +1,13 @@
1
+ import { type RuntimeDiagnostics } from "./runtime-state";
1
2
  import type { RepostClientOptions, SchemaDescriptor, Transport } from "./types";
3
+ /**
4
+ * The descriptor-format version this runtime implements. Generated clients
5
+ * declare the version they were emitted for; [`buildWebhooks`] refuses a
6
+ * mismatch at construction — never silently at send time. Bumped only on a
7
+ * wire-breaking change to the descriptor contract (see
8
+ * sdk/conformance/CONTRACT.md and the conformance-vector freeze policy).
9
+ */
10
+ export declare const DESCRIPTOR_FORMAT_VERSION = 2;
2
11
  /**
3
12
  * No-network transport for tests: echoes the envelope identity as a typed
4
13
  * `SendResult` with a fixed stub message id.
@@ -11,3 +20,9 @@ export declare const stubTransport: Transport;
11
20
  * from the same catalog.
12
21
  */
13
22
  export declare function buildWebhooks<T>(options: RepostClientOptions, schema: SchemaDescriptor): T;
23
+ /** Build the generated webhooks tree and its credential-free diagnostics surface. */
24
+ export declare function buildClient<T>(options: RepostClientOptions, schema: SchemaDescriptor): {
25
+ readonly webhooks: T;
26
+ diagnostics(): RuntimeDiagnostics;
27
+ close(): void;
28
+ };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ /** Package version embedded in runtime identifiers and telemetry instruments. */
4
+ const PACKAGE_VERSION = "0.4.0";
5
+
6
+ exports.PACKAGE_VERSION = PACKAGE_VERSION;
7
+ //# sourceMappingURL=version-CGqSWJir.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-CGqSWJir.cjs","sources":["../../../src/version.ts"],"sourcesContent":["/** Package version embedded in runtime identifiers and telemetry instruments. */\nexport const PACKAGE_VERSION = \"0.4.0\";\n"],"names":[],"mappings":";;AAAA;AACO,MAAM,eAAe,GAAG;;;;"}