@stratasync/transport-graphql 0.2.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.
@@ -0,0 +1,33 @@
1
+ import type { MutateResult, TransactionBatch } from "@stratasync/core";
2
+ import type { AuthProvider, GraphQLMutationBuilder, RetryConfig } from "./types.js";
3
+ export interface SendRestMutationsOptions {
4
+ endpoint: string;
5
+ batch: TransactionBatch;
6
+ auth: AuthProvider;
7
+ headers?: Record<string, string>;
8
+ retryConfig?: RetryConfig;
9
+ timeoutMs?: number;
10
+ }
11
+ /**
12
+ * Sends mutations via REST endpoint (no GraphQL)
13
+ * Used when no mutationBuilder is configured
14
+ */
15
+ export declare const sendRestMutations: (opts: SendRestMutationsOptions) => Promise<MutateResult>;
16
+ export interface SendMutationsOptions {
17
+ endpoint: string;
18
+ batch: TransactionBatch;
19
+ auth: AuthProvider;
20
+ headers?: Record<string, string>;
21
+ retryConfig?: RetryConfig;
22
+ timeoutMs?: number;
23
+ mutationBuilder: GraphQLMutationBuilder;
24
+ }
25
+ /**
26
+ * Sends a batch of mutations to the server via GraphQL
27
+ */
28
+ export declare const sendMutations: (opts: SendMutationsOptions) => Promise<MutateResult>;
29
+ /**
30
+ * Checks if an error indicates auth failure
31
+ */
32
+ export declare const isAuthError: (error: unknown) => boolean;
33
+ //# sourceMappingURL=mutations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutations.d.ts","sourceRoot":"","sources":["../src/mutations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAEZ,gBAAgB,EAEjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAAK,EACV,YAAY,EAEZ,sBAAsB,EAEtB,WAAW,EACZ,MAAM,YAAY,CAAC;AAwMpB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,gBAAgB,CAAC;IACxB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,wBAAwB,KAC7B,OAAO,CAAC,YAAY,CAoEtB,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,gBAAgB,CAAC;IACxB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,sBAAsB,CAAC;CACzC;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,GACxB,MAAM,oBAAoB,KACzB,OAAO,CAAC,YAAY,CAyCtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,OAU5C,CAAC"}
@@ -0,0 +1,225 @@
1
+ import { maxSyncId, ZERO_SYNC_ID } from "@stratasync/core";
2
+ import { buildRequestHeaders, fetchChecked, isRetryableError, parseSyncId, resolveAuthToken, retryWithBackoff, } from "./utils.js";
3
+ /**
4
+ * Maps internal action codes to GraphQL action names
5
+ */
6
+ const mapActionToGraphQL = (action) => {
7
+ const mapping = {
8
+ A: "ARCHIVE",
9
+ D: "DELETE",
10
+ I: "INSERT",
11
+ U: "UPDATE",
12
+ V: "UNARCHIVE",
13
+ };
14
+ return mapping[action] ?? action;
15
+ };
16
+ const mergeInto = (target, source, label) => {
17
+ if (!source) {
18
+ return;
19
+ }
20
+ for (const [key, value] of Object.entries(source)) {
21
+ if (key in target) {
22
+ throw new Error(`Duplicate GraphQL ${label}: ${key}`);
23
+ }
24
+ target[key] = value;
25
+ }
26
+ };
27
+ const buildMutationPayload = (batch, mutationBuilder) => {
28
+ const mutationSpecs = batch.transactions.map((tx, index) => mutationBuilder(tx, index));
29
+ const aliasMap = new Map();
30
+ const fields = [];
31
+ const variables = {};
32
+ const variableTypes = {};
33
+ for (const [index, spec] of mutationSpecs.entries()) {
34
+ const alias = `t${index}`;
35
+ const tx = batch.transactions[index];
36
+ if (!tx) {
37
+ continue;
38
+ }
39
+ aliasMap.set(alias, tx.clientTxId);
40
+ fields.push(`${alias}: ${spec.mutation}`);
41
+ mergeInto(variables, spec.variables, "variable");
42
+ mergeInto(variableTypes, spec.variableTypes, "variable type");
43
+ }
44
+ const variableDefs = Object.entries(variableTypes)
45
+ .map(([key, type]) => `$${key}: ${type}`)
46
+ .join(", ");
47
+ const query = `mutation SyncBatch${variableDefs ? `(${variableDefs})` : ""} { ${fields.join(" ")} }`;
48
+ return { aliasMap, query, variables };
49
+ };
50
+ const collectGraphQLErrors = (errors) => {
51
+ const errorsByAlias = new Map();
52
+ const unscopedErrors = [];
53
+ if (!errors?.length) {
54
+ return { errorsByAlias, unscopedErrors };
55
+ }
56
+ for (const error of errors) {
57
+ const pathAlias = error.path?.[0];
58
+ if (typeof pathAlias === "string") {
59
+ const existing = errorsByAlias.get(pathAlias) ?? [];
60
+ existing.push(error.message);
61
+ errorsByAlias.set(pathAlias, existing);
62
+ }
63
+ else {
64
+ unscopedErrors.push(error.message);
65
+ }
66
+ }
67
+ return { errorsByAlias, unscopedErrors };
68
+ };
69
+ const parseMutationResults = (response, aliasMap) => {
70
+ if (!response.data) {
71
+ throw new Error("No data in mutation response");
72
+ }
73
+ const { errorsByAlias, unscopedErrors } = collectGraphQLErrors(response.errors);
74
+ if (unscopedErrors.length > 0) {
75
+ throw new Error(`GraphQL errors: ${unscopedErrors.join(", ")}`);
76
+ }
77
+ const results = [];
78
+ let lastSyncId = ZERO_SYNC_ID;
79
+ let success = true;
80
+ for (const [alias, clientTxId] of aliasMap.entries()) {
81
+ const aliasErrors = errorsByAlias.get(alias);
82
+ if (aliasErrors) {
83
+ results.push({
84
+ clientTxId,
85
+ error: aliasErrors.join(", "),
86
+ success: false,
87
+ });
88
+ success = false;
89
+ continue;
90
+ }
91
+ const payload = response.data[alias];
92
+ if (!payload || typeof payload !== "object") {
93
+ results.push({
94
+ clientTxId,
95
+ error: "Missing mutation response",
96
+ success: false,
97
+ });
98
+ success = false;
99
+ continue;
100
+ }
101
+ const payloadRecord = payload;
102
+ if (payloadRecord.success === false) {
103
+ results.push({
104
+ clientTxId,
105
+ error: typeof payloadRecord.error === "string"
106
+ ? payloadRecord.error
107
+ : "Mutation failed",
108
+ success: false,
109
+ });
110
+ success = false;
111
+ continue;
112
+ }
113
+ const syncIdRaw = payloadRecord.syncId;
114
+ const syncId = syncIdRaw === undefined
115
+ ? undefined
116
+ : parseSyncId(syncIdRaw, `Mutation response ${alias} syncId`);
117
+ if (syncId !== undefined) {
118
+ lastSyncId = maxSyncId(lastSyncId, syncId);
119
+ }
120
+ results.push({
121
+ clientTxId,
122
+ success: true,
123
+ ...(syncId !== undefined && { syncId }),
124
+ });
125
+ }
126
+ return {
127
+ lastSyncId,
128
+ results,
129
+ success,
130
+ };
131
+ };
132
+ /**
133
+ * Sends mutations via REST endpoint (no GraphQL)
134
+ * Used when no mutationBuilder is configured
135
+ */
136
+ export const sendRestMutations = async (opts) => {
137
+ if (opts.batch.transactions.length === 0) {
138
+ return {
139
+ lastSyncId: ZERO_SYNC_ID,
140
+ results: [],
141
+ success: true,
142
+ };
143
+ }
144
+ const response = await retryWithBackoff(async () => {
145
+ const token = await resolveAuthToken(opts.auth);
146
+ const requestHeaders = buildRequestHeaders({
147
+ contentType: "application/json",
148
+ headers: opts.headers,
149
+ token,
150
+ });
151
+ const body = JSON.stringify({
152
+ batchId: opts.batch.batchId,
153
+ transactions: opts.batch.transactions.map((tx) => ({
154
+ action: mapActionToGraphQL(tx.action),
155
+ clientId: tx.clientId,
156
+ clientTxId: tx.clientTxId,
157
+ modelId: tx.modelId,
158
+ modelName: tx.modelName,
159
+ payload: tx.action === "D" && tx.original
160
+ ? { ...tx.original, ...tx.payload }
161
+ : tx.payload,
162
+ })),
163
+ });
164
+ const res = await fetchChecked(opts.endpoint, { body, headers: requestHeaders, method: "POST" }, opts.timeoutMs, "Mutation failed");
165
+ return res.json();
166
+ }, opts.retryConfig, isRetryableError);
167
+ return {
168
+ lastSyncId: parseSyncId(response.lastSyncId, "Mutation response lastSyncId"),
169
+ results: response.results.map((r) => {
170
+ const result = {
171
+ clientTxId: r.clientTxId,
172
+ success: r.success,
173
+ };
174
+ if (r.syncId !== undefined) {
175
+ result.syncId = parseSyncId(r.syncId, `Mutation response result ${r.clientTxId} syncId`);
176
+ }
177
+ if (r.error !== undefined) {
178
+ result.error = r.error;
179
+ }
180
+ return result;
181
+ }),
182
+ success: response.success,
183
+ };
184
+ };
185
+ /**
186
+ * Sends a batch of mutations to the server via GraphQL
187
+ */
188
+ export const sendMutations = async (opts) => {
189
+ if (opts.batch.transactions.length === 0) {
190
+ return {
191
+ lastSyncId: ZERO_SYNC_ID,
192
+ results: [],
193
+ success: true,
194
+ };
195
+ }
196
+ const { aliasMap, query, variables } = buildMutationPayload(opts.batch, opts.mutationBuilder);
197
+ const response = await retryWithBackoff(async () => {
198
+ const token = await resolveAuthToken(opts.auth);
199
+ const requestHeaders = buildRequestHeaders({
200
+ contentType: "application/json",
201
+ headers: opts.headers,
202
+ token,
203
+ });
204
+ const body = JSON.stringify({
205
+ query,
206
+ variables,
207
+ });
208
+ const res = await fetchChecked(opts.endpoint, { body, headers: requestHeaders, method: "POST" }, opts.timeoutMs, "Mutation failed");
209
+ return res.json();
210
+ }, opts.retryConfig, isRetryableError);
211
+ return parseMutationResults(response, aliasMap);
212
+ };
213
+ /**
214
+ * Checks if an error indicates auth failure
215
+ */
216
+ export const isAuthError = (error) => {
217
+ if (error instanceof Error) {
218
+ return (error.message.includes("401") ||
219
+ error.message.includes("403") ||
220
+ error.message.includes("Unauthorized") ||
221
+ error.message.includes("Forbidden"));
222
+ }
223
+ return false;
224
+ };
225
+ //# sourceMappingURL=mutations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutations.js","sourceRoot":"","sources":["../src/mutations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { DeltaPacket } from "@stratasync/core";
2
+ /**
3
+ * Normalizes a sync endpoint to its base path (e.g., /sync)
4
+ */
5
+ export declare const normalizeSyncEndpoint: (endpoint: string) => string;
6
+ /**
7
+ * Joins a base URL with a path segment
8
+ */
9
+ export declare const joinSyncUrl: (base: string, path: string) => string;
10
+ /**
11
+ * Parses a raw delta packet payload into a DeltaPacket
12
+ */
13
+ export declare const parseDeltaPacket: (raw: unknown) => DeltaPacket | null;
14
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAGZ,MAAM,kBAAkB,CAAC;AAQ1B;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,MAQxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,MAAM,EAAE,MAAM,MAAM,KAAG,MAIxD,CAAC;AAsFF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,KAAK,OAAO,KAAG,WAAW,GAAG,IAgE7D,CAAC"}
@@ -0,0 +1,144 @@
1
+ import { maxSyncId, ZERO_SYNC_ID } from "@stratasync/core";
2
+ import { parseSyncId } from "./utils.js";
3
+ const SYNC_ENDPOINT_SUFFIXES = ["/bootstrap", "/batch", "/deltas"];
4
+ const TRAILING_SLASH_RE = /\/+$/;
5
+ /**
6
+ * Normalizes a sync endpoint to its base path (e.g., /sync)
7
+ */
8
+ export const normalizeSyncEndpoint = (endpoint) => {
9
+ const trimmed = endpoint.replace(TRAILING_SLASH_RE, "");
10
+ for (const suffix of SYNC_ENDPOINT_SUFFIXES) {
11
+ if (trimmed.endsWith(suffix)) {
12
+ return trimmed.slice(0, -suffix.length);
13
+ }
14
+ }
15
+ return trimmed;
16
+ };
17
+ /**
18
+ * Joins a base URL with a path segment
19
+ */
20
+ export const joinSyncUrl = (base, path) => {
21
+ const normalizedBase = base.replace(TRAILING_SLASH_RE, "");
22
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
23
+ return `${normalizedBase}${normalizedPath}`;
24
+ };
25
+ /**
26
+ * Maps action strings to internal action codes
27
+ */
28
+ const normalizeAction = (action) => {
29
+ if (action === "I" ||
30
+ action === "U" ||
31
+ action === "D" ||
32
+ action === "A" ||
33
+ action === "V" ||
34
+ action === "C" ||
35
+ action === "G" ||
36
+ action === "S") {
37
+ return action;
38
+ }
39
+ throw new Error(`Unknown action: ${action}`);
40
+ };
41
+ /**
42
+ * Parses a raw sync action payload into a SyncAction
43
+ */
44
+ const parseSyncAction = (raw) => {
45
+ const syncIdRaw = raw.syncId ?? raw.id;
46
+ if (syncIdRaw === undefined) {
47
+ throw new TypeError("Sync action is missing syncId/id");
48
+ }
49
+ const parsedSyncId = parseSyncId(syncIdRaw, "Sync action syncId/id");
50
+ const { modelName } = raw;
51
+ if (typeof modelName !== "string") {
52
+ throw new TypeError("Sync action is missing modelName");
53
+ }
54
+ const { modelId } = raw;
55
+ if (typeof modelId !== "string") {
56
+ throw new TypeError("Sync action is missing modelId");
57
+ }
58
+ const actionRaw = raw.action;
59
+ if (typeof actionRaw !== "string") {
60
+ throw new TypeError("Sync action is missing action");
61
+ }
62
+ const createdAtRaw = raw.createdAt;
63
+ let createdAt;
64
+ if (typeof createdAtRaw === "string" || typeof createdAtRaw === "number") {
65
+ createdAt = new Date(createdAtRaw);
66
+ }
67
+ const groupsRaw = raw.groups;
68
+ const groups = Array.isArray(groupsRaw)
69
+ ? groupsRaw.filter((group) => typeof group === "string")
70
+ : undefined;
71
+ const groupId = typeof raw.groupId === "string" ? raw.groupId : undefined;
72
+ const result = {
73
+ action: normalizeAction(actionRaw),
74
+ data: raw.data ?? {},
75
+ id: parsedSyncId,
76
+ modelId,
77
+ modelName,
78
+ };
79
+ if (groupId !== undefined) {
80
+ result.groupId = groupId;
81
+ }
82
+ if (groups !== undefined) {
83
+ result.groups = groups;
84
+ }
85
+ if (typeof raw.clientTxId === "string") {
86
+ result.clientTxId = raw.clientTxId;
87
+ }
88
+ if (typeof raw.clientId === "string") {
89
+ result.clientId = raw.clientId;
90
+ }
91
+ if (createdAt !== undefined) {
92
+ result.createdAt = createdAt;
93
+ }
94
+ return result;
95
+ };
96
+ /**
97
+ * Parses a raw delta packet payload into a DeltaPacket
98
+ */
99
+ export const parseDeltaPacket = (raw) => {
100
+ if (Array.isArray(raw)) {
101
+ const actions = raw
102
+ .filter((item) => typeof item === "object" && item !== null)
103
+ .map((item) => parseSyncAction(item));
104
+ // oxlint-disable-next-line no-array-reduce
105
+ const lastSyncId = actions.reduce((max, action) => maxSyncId(max, action.id), ZERO_SYNC_ID);
106
+ return { actions, lastSyncId };
107
+ }
108
+ if (typeof raw !== "object" || raw === null) {
109
+ return null;
110
+ }
111
+ const payload = raw;
112
+ if (payload.type === "delta" &&
113
+ payload.packet &&
114
+ typeof payload.packet === "object") {
115
+ return parseDeltaPacket(payload.packet);
116
+ }
117
+ if (Array.isArray(payload.actions)) {
118
+ const actions = payload.actions.map((action) => parseSyncAction(action));
119
+ const lastSyncIdRaw = payload.lastSyncId;
120
+ const lastSyncId =
121
+ // oxlint-disable-next-line no-array-reduce
122
+ lastSyncIdRaw === undefined
123
+ ? // oxlint-disable-next-line no-array-reduce
124
+ actions.reduce((max, action) => maxSyncId(max, action.id), ZERO_SYNC_ID)
125
+ : parseSyncId(lastSyncIdRaw, "Delta packet lastSyncId");
126
+ const packet = {
127
+ actions,
128
+ lastSyncId,
129
+ };
130
+ if (typeof payload.hasMore === "boolean") {
131
+ packet.hasMore = payload.hasMore;
132
+ }
133
+ return packet;
134
+ }
135
+ if (payload.action && payload.modelName && payload.modelId) {
136
+ const action = parseSyncAction(payload);
137
+ return {
138
+ actions: [action],
139
+ lastSyncId: action.id,
140
+ };
141
+ }
142
+ return null;
143
+ };
144
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ import type { Transaction } from "@stratasync/core";
2
+ /**
3
+ * Authentication provider interface
4
+ */
5
+ export interface AuthProvider {
6
+ /** Gets the current access token */
7
+ getAccessToken(): Promise<string | null>;
8
+ /** Refreshes the access token */
9
+ refreshToken?(): Promise<string | null>;
10
+ /** Called when auth fails */
11
+ onAuthError?(error: Error): void;
12
+ }
13
+ /**
14
+ * Transport adapter options
15
+ */
16
+ export interface TransportOptions {
17
+ /** GraphQL endpoint URL */
18
+ endpoint: string;
19
+ /** Base REST sync endpoint (e.g., https://api.example.com/sync) */
20
+ syncEndpoint: string;
21
+ /** WebSocket endpoint for subscriptions */
22
+ wsEndpoint: string;
23
+ /** Authentication provider */
24
+ auth: AuthProvider;
25
+ /** GraphQL mutation builder */
26
+ mutationBuilder?: GraphQLMutationBuilder;
27
+ /** Request timeout in milliseconds */
28
+ timeout?: number;
29
+ /** Retry configuration */
30
+ retry?: RetryConfig;
31
+ /** Custom headers */
32
+ headers?: Record<string, string>;
33
+ /** Custom WebSocket implementation (for non-browser environments) */
34
+ webSocketFactory?: typeof WebSocket;
35
+ }
36
+ /**
37
+ * Retry configuration
38
+ */
39
+ export interface RetryConfig {
40
+ /** Maximum number of retries */
41
+ maxRetries: number;
42
+ /** Base delay in milliseconds */
43
+ baseDelay: number;
44
+ /** Maximum delay in milliseconds */
45
+ maxDelay: number;
46
+ /** Jitter factor (0-1) */
47
+ jitter?: number;
48
+ }
49
+ /**
50
+ * Default retry configuration
51
+ */
52
+ export declare const DEFAULT_RETRY_CONFIG: RetryConfig;
53
+ /**
54
+ * GraphQL error structure
55
+ */
56
+ export interface GraphQLError {
57
+ message: string;
58
+ locations?: {
59
+ line: number;
60
+ column: number;
61
+ }[];
62
+ path?: (string | number)[];
63
+ extensions?: {
64
+ code?: string;
65
+ [key: string]: unknown;
66
+ };
67
+ }
68
+ /**
69
+ * GraphQL response structure
70
+ */
71
+ export interface GraphQLResponse<T> {
72
+ data?: T;
73
+ errors?: GraphQLError[];
74
+ }
75
+ /**
76
+ * GraphQL mutation specification for a single transaction
77
+ */
78
+ export interface GraphQLMutationSpec {
79
+ /** GraphQL field invocation (e.g. taskUpdate(...){ syncId }) */
80
+ mutation: string;
81
+ /** Variables used by the mutation */
82
+ variables?: Record<string, unknown>;
83
+ /** GraphQL variable types */
84
+ variableTypes?: Record<string, string>;
85
+ }
86
+ /**
87
+ * Builds a GraphQL mutation for a transaction
88
+ */
89
+ export type GraphQLMutationBuilder = (transaction: Transaction, index: number) => GraphQLMutationSpec;
90
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,iCAAiC;IACjC,YAAY,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxC,6BAA6B;IAC7B,WAAW,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,IAAI,EAAE,YAAY,CAAC;IACnB,+BAA+B;IAC/B,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,qBAAqB;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,OAAO,SAAS,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAKlC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/C,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,6BAA6B;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,CACnC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,MAAM,KACV,mBAAmB,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Default retry configuration
3
+ */
4
+ export const DEFAULT_RETRY_CONFIG = {
5
+ baseDelay: 1000,
6
+ jitter: 0.2,
7
+ maxDelay: 30_000,
8
+ maxRetries: 3,
9
+ };
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAoDA;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAC/C,SAAS,EAAE,IAAI;IACf,MAAM,EAAE,GAAG;IACX,QAAQ,EAAE,MAAM;IAChB,UAAU,EAAE,CAAC;CACd,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { AuthProvider, RetryConfig } from "./types.js";
2
+ /**
3
+ * Calculates the delay for exponential backoff with jitter
4
+ */
5
+ export declare const calculateBackoff: (attempt: number, config: RetryConfig) => number;
6
+ /**
7
+ * Retries an async function with exponential backoff
8
+ */
9
+ export declare const retryWithBackoff: <T>(fn: () => Promise<T>, config?: RetryConfig, shouldRetry?: (error: unknown) => boolean) => Promise<T>;
10
+ interface RequestHeaderOptions {
11
+ token: string | null;
12
+ headers?: Record<string, string>;
13
+ accept?: string;
14
+ contentType?: string;
15
+ }
16
+ /**
17
+ * Builds request headers with auth token, accept, content-type, and custom headers
18
+ */
19
+ export declare const buildRequestHeaders: (opts: RequestHeaderOptions) => Record<string, string>;
20
+ /**
21
+ * HTTP error with status code for robust error classification
22
+ */
23
+ export declare class HttpError extends Error {
24
+ readonly status: number;
25
+ constructor(status: number, message: string);
26
+ }
27
+ /**
28
+ * Fetches a URL with optional timeout and checks for a successful response
29
+ */
30
+ export declare const fetchChecked: (url: string, init: RequestInit, timeoutMs: number | undefined, errorPrefix: string) => Promise<Response>;
31
+ /**
32
+ * Checks if an error is a network error
33
+ */
34
+ export declare const isNetworkError: (error: unknown) => boolean;
35
+ /**
36
+ * Checks if an error is a timeout error
37
+ */
38
+ export declare const isTimeoutError: (error: unknown) => boolean;
39
+ /**
40
+ * Checks if an error is retryable
41
+ */
42
+ export declare const isRetryableError: (error: unknown) => boolean;
43
+ /**
44
+ * Validates a string-encoded sync ID.
45
+ */
46
+ export declare const parseSyncId: (value: unknown, fieldName?: string) => string;
47
+ /**
48
+ * Resolves an auth token, falling back to refreshToken if available
49
+ */
50
+ export declare const resolveAuthToken: (auth: AuthProvider) => Promise<string | null>;
51
+ export {};
52
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAY5D;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,SAAS,MAAM,EACf,QAAQ,WAAW,KAClB,MAYF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAU,CAAC,EACtC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,SAAQ,WAAkC,EAC1C,cAAa,CAAC,KAAK,EAAE,OAAO,KAAK,OAAoB,KACpD,OAAO,CAAC,CAAC,CAoBX,CAAC;AA4CF,UAAU,oBAAoB;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,MAAM,oBAAoB,KACzB,MAAM,CAAC,MAAM,EAAE,MAAM,CAmBvB,CAAC;AAEF;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK5C;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,GACvB,KAAK,MAAM,EACX,MAAM,WAAW,EACjB,WAAW,MAAM,GAAG,SAAS,EAC7B,aAAa,MAAM,KAClB,OAAO,CAAC,QAAQ,CAWlB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,OAY/C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,OAS/C,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,OAAO,KAAG,OAejD,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,EAAE,kBAAoB,KAAG,MAUlE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,YAAY,KACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAMvB,CAAC"}