@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.
- package/README.md +45 -0
- package/dist/adapter.d.ts +31 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +151 -0
- package/dist/adapter.js.map +1 -0
- package/dist/bootstrap.d.ts +27 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +223 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/deltas.d.ts +31 -0
- package/dist/deltas.d.ts.map +1 -0
- package/dist/deltas.js +69 -0
- package/dist/deltas.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/mutations.d.ts +33 -0
- package/dist/mutations.d.ts.map +1 -0
- package/dist/mutations.js +225 -0
- package/dist/mutations.js.map +1 -0
- package/dist/protocol.d.ts +14 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +144 -0
- package/dist/protocol.js.map +1 -0
- package/dist/types.d.ts +90 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +52 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +180 -0
- package/dist/utils.js.map +1 -0
- package/dist/websocket.d.ts +75 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +482 -0
- package/dist/websocket.js.map +1 -0
- package/dist/yjs-transport.d.ts +18 -0
- package/dist/yjs-transport.d.ts.map +1 -0
- package/dist/yjs-transport.js +53 -0
- package/dist/yjs-transport.js.map +1 -0
- package/package.json +42 -0
|
@@ -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":"AAMA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAS3D,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,kBAAkB,GAAG,CAAC,MAAc,EAAU,EAAE;IACpD,MAAM,OAAO,GAA2B;QACtC,CAAC,EAAE,SAAS;QACZ,CAAC,EAAE,QAAQ;QACX,CAAC,EAAE,QAAQ;QACX,CAAC,EAAE,QAAQ;QACX,CAAC,EAAE,WAAW;KACf,CAAC;IACF,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC;AACnC,CAAC,CAAC;AAmBF,MAAM,SAAS,GAAG,CAChB,MAAyB,EACzB,MAAqC,EACrC,KAAa,EACP,EAAE;IACR,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,qBAAqB,KAAK,KAAK,GAAG,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACtB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAC3B,KAAuB,EACvB,eAAuC,EACtB,EAAE;IACnB,MAAM,aAAa,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CACzD,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,CAC3B,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,MAAM,aAAa,GAA2B,EAAE,CAAC;IAEjD,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE1C,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACjD,SAAS,CAAC,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;SAC/C,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;SACxC,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,KAAK,GAAG,qBAAqB,YAAY,CAAC,CAAC,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IAErG,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AACxC,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAC3B,MAAuB,EAIvB,EAAE;IACF,MAAM,aAAa,GAAG,IAAI,GAAG,EAAoB,CAAC;IAClD,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QACpB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;IAC3C,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;YACpD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAC3B,QAAkD,EAClD,QAA6B,EACf,EAAE;IAChB,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,oBAAoB,CAC5D,QAAQ,CAAC,MAAM,CAChB,CAAC;IAEF,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,mBAAmB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,IAAI,UAAU,GAAW,YAAY,CAAC;IACtC,IAAI,OAAO,GAAG,IAAI,CAAC;IAEnB,KAAK,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QACrD,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC;gBACX,UAAU;gBACV,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC7B,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;YACH,OAAO,GAAG,KAAK,CAAC;YAChB,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,OAAO,CAAC,IAAI,CAAC;gBACX,UAAU;gBACV,KAAK,EAAE,2BAA2B;gBAClC,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;YACH,OAAO,GAAG,KAAK,CAAC;YAChB,SAAS;QACX,CAAC;QAED,MAAM,aAAa,GAAG,OAAkC,CAAC;QACzD,IAAI,aAAa,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC;gBACX,UAAU;gBACV,KAAK,EACH,OAAO,aAAa,CAAC,KAAK,KAAK,QAAQ;oBACrC,CAAC,CAAC,aAAa,CAAC,KAAK;oBACrB,CAAC,CAAC,iBAAiB;gBACvB,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;YACH,OAAO,GAAG,KAAK,CAAC;YAChB,SAAS;QACX,CAAC;QAED,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC;QACvC,MAAM,MAAM,GACV,SAAS,KAAK,SAAS;YACrB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,WAAW,CAAC,SAAS,EAAE,qBAAqB,KAAK,SAAS,CAAC,CAAC;QAElE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,UAAU,GAAG,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,CAAC,IAAI,CAAC;YACX,UAAU;YACV,OAAO,EAAE,IAAI;YACb,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;SACxC,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,UAAU;QACV,OAAO;QACP,OAAO;KACR,CAAC;AACJ,CAAC,CAAC;AAWF;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,EACpC,IAA8B,EACP,EAAE;IACzB,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,UAAU,EAAE,YAAY;YACxB,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CACrC,KAAK,IAAI,EAAE;QACT,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,cAAc,GAAG,mBAAmB,CAAC;YACzC,WAAW,EAAE,kBAAkB;YAC/B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK;SACN,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;YAC3B,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBACjD,MAAM,EAAE,kBAAkB,CAAC,EAAE,CAAC,MAAM,CAAC;gBACrC,QAAQ,EAAE,EAAE,CAAC,QAAQ;gBACrB,UAAU,EAAE,EAAE,CAAC,UAAU;gBACzB,OAAO,EAAE,EAAE,CAAC,OAAO;gBACnB,SAAS,EAAE,EAAE,CAAC,SAAS;gBACvB,OAAO,EACL,EAAE,CAAC,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC,QAAQ;oBAC9B,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE;oBACnC,CAAC,CAAC,EAAE,CAAC,OAAO;aACjB,CAAC,CAAC;SACJ,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,MAAM,YAAY,CAC5B,IAAI,CAAC,QAAQ,EACb,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,EACjD,IAAI,CAAC,SAAS,EACd,iBAAiB,CAClB,CAAC;QAEF,OAAO,GAAG,CAAC,IAAI,EAAiC,CAAC;IACnD,CAAC,EACD,IAAI,CAAC,WAAW,EAChB,gBAAgB,CACjB,CAAC;IAEF,OAAO;QACL,UAAU,EAAE,WAAW,CACrB,QAAQ,CAAC,UAAU,EACnB,8BAA8B,CAC/B;QACD,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAClC,MAAM,MAAM,GAAsB;gBAChC,UAAU,EAAE,CAAC,CAAC,UAAU;gBACxB,OAAO,EAAE,CAAC,CAAC,OAAO;aACnB,CAAC;YACF,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC3B,MAAM,CAAC,MAAM,GAAG,WAAW,CACzB,CAAC,CAAC,MAAM,EACR,4BAA4B,CAAC,CAAC,UAAU,SAAS,CAClD,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC1B,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;YACzB,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;QACF,OAAO,EAAE,QAAQ,CAAC,OAAO;KAC1B,CAAC;AACJ,CAAC,CAAC;AAYF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,IAA0B,EACH,EAAE;IACzB,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzC,OAAO;YACL,UAAU,EAAE,YAAY;YACxB,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,oBAAoB,CACzD,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,eAAe,CACrB,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CACrC,KAAK,IAAI,EAAE;QACT,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,cAAc,GAAG,mBAAmB,CAAC;YACzC,WAAW,EAAE,kBAAkB;YAC/B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK;SACN,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,KAAK;YACL,SAAS;SACV,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,MAAM,YAAY,CAC5B,IAAI,CAAC,QAAQ,EACb,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,EACjD,IAAI,CAAC,SAAS,EACd,iBAAiB,CAClB,CAAC;QAEF,OAAO,GAAG,CAAC,IAAI,EAAuD,CAAC;IACzE,CAAC,EACD,IAAI,CAAC,WAAW,EAChB,gBAAgB,CACjB,CAAC;IAEF,OAAO,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAc,EAAW,EAAE;IACrD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC7B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC7B,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;YACtC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CACpC,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
|
|
@@ -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"}
|
package/dist/protocol.js
ADDED
|
@@ -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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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -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"}
|