use-abcd 1.1.0 → 1.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.
- package/dist/chunks/client-DReyDQ23.js +144 -0
- package/dist/chunks/client-DReyDQ23.js.map +1 -0
- package/dist/chunks/types-Dy4rYb2N.js.map +1 -1
- package/dist/collection.d.ts +1 -0
- package/dist/fetch-handler.d.ts +1 -0
- package/dist/index.js +551 -535
- package/dist/index.js.map +1 -1
- package/dist/runtime/client.d.ts +1 -0
- package/dist/runtime/client.js +1 -1
- package/dist/runtime/server.d.ts +17 -13
- package/dist/runtime/server.js +39 -39
- package/dist/runtime/server.js.map +1 -1
- package/dist/runtime/types.d.ts +2 -0
- package/dist/sync-queue.d.ts +1 -0
- package/package.json +1 -1
- package/dist/chunks/client-VrsFvEIA.js +0 -144
- package/dist/chunks/client-VrsFvEIA.js.map +0 -1
package/dist/runtime/client.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export declare function syncError(error: string): SyncHandlerResult;
|
|
|
42
42
|
export type EndpointSyncClientConfig = {
|
|
43
43
|
endpoint: string;
|
|
44
44
|
headers?: Record<string, string>;
|
|
45
|
+
scope?: string;
|
|
45
46
|
};
|
|
46
47
|
export type EndpointSyncClient<T, Q = unknown> = {
|
|
47
48
|
onFetch: (query: Q, signal: AbortSignal) => Promise<T[]>;
|
package/dist/runtime/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c } from "../chunks/types-Dy4rYb2N.js";
|
|
2
|
-
import { c as t, b as a, a as n, f as o, d as S, s as y } from "../chunks/client-
|
|
2
|
+
import { c as t, b as a, a as n, f as o, d as S, s as y } from "../chunks/client-DReyDQ23.js";
|
|
3
3
|
import { createSyncServer as f, serverSyncError as l, serverSyncSuccess as m } from "./server.js";
|
|
4
4
|
export {
|
|
5
5
|
c as categorizeResults,
|
package/dist/runtime/server.d.ts
CHANGED
|
@@ -2,28 +2,32 @@ import { Change, SyncResult } from '../types';
|
|
|
2
2
|
import { SyncHandlerResult, SyncBatchResult, Schema, SyncRequestBody, SyncResponseBody, categorizeResults } from './types';
|
|
3
3
|
export type { SyncHandlerResult, SyncBatchResult, Schema, SyncRequestBody, SyncResponseBody };
|
|
4
4
|
export { categorizeResults };
|
|
5
|
-
|
|
6
|
-
export type
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
/** Context passed to all handlers containing the parsed request body */
|
|
6
|
+
export type ServerHandlerContext<T, Q = unknown> = {
|
|
7
|
+
body: SyncRequestBody<T, Q>;
|
|
8
|
+
};
|
|
9
|
+
export type ServerFetchHandler<T, Q> = (query: Q, ctx: ServerHandlerContext<T, Q>) => Promise<T[]> | T[];
|
|
10
|
+
export type ServerCreateHandler<T, Q = unknown> = (data: T, ctx: ServerHandlerContext<T, Q>) => Promise<SyncHandlerResult> | SyncHandlerResult;
|
|
11
|
+
export type ServerUpdateHandler<T, Q = unknown> = (id: string, data: T, ctx: ServerHandlerContext<T, Q>) => Promise<SyncHandlerResult> | SyncHandlerResult;
|
|
12
|
+
export type ServerDeleteHandler<T, Q = unknown> = (id: string, data: T, ctx: ServerHandlerContext<T, Q>) => Promise<SyncHandlerResult> | SyncHandlerResult;
|
|
9
13
|
export type ServerSyncHandlerConfig<T, Q = unknown> = {
|
|
10
14
|
schema?: Schema<T>;
|
|
11
15
|
querySchema?: Schema<Q>;
|
|
12
16
|
fetch?: ServerFetchHandler<T, Q>;
|
|
13
|
-
create?: ServerCreateHandler<T>;
|
|
14
|
-
update?: ServerUpdateHandler<T>;
|
|
15
|
-
delete?: ServerDeleteHandler<T>;
|
|
17
|
+
create?: ServerCreateHandler<T, Q>;
|
|
18
|
+
update?: ServerUpdateHandler<T, Q>;
|
|
19
|
+
delete?: ServerDeleteHandler<T, Q>;
|
|
16
20
|
};
|
|
17
21
|
export type ServerSyncHandler<T, Q = unknown> = {
|
|
18
22
|
handler: (request: Request) => Promise<Response>;
|
|
19
|
-
fetchItems: (query: Q) => Promise<T[]>;
|
|
20
|
-
processChanges: (changes: Change<T>[]) => Promise<SyncResult[]>;
|
|
21
|
-
processChangesWithStats: (changes: Change<T>[]) => Promise<SyncBatchResult>;
|
|
23
|
+
fetchItems: (query: Q, ctx: ServerHandlerContext<T, Q>) => Promise<T[]>;
|
|
24
|
+
processChanges: (changes: Change<T>[], ctx: ServerHandlerContext<T, Q>) => Promise<SyncResult[]>;
|
|
25
|
+
processChangesWithStats: (changes: Change<T>[], ctx: ServerHandlerContext<T, Q>) => Promise<SyncBatchResult>;
|
|
22
26
|
handlers: {
|
|
23
27
|
fetch?: ServerFetchHandler<T, Q>;
|
|
24
|
-
create?: ServerCreateHandler<T>;
|
|
25
|
-
update?: ServerUpdateHandler<T>;
|
|
26
|
-
delete?: ServerDeleteHandler<T>;
|
|
28
|
+
create?: ServerCreateHandler<T, Q>;
|
|
29
|
+
update?: ServerUpdateHandler<T, Q>;
|
|
30
|
+
delete?: ServerDeleteHandler<T, Q>;
|
|
27
31
|
};
|
|
28
32
|
};
|
|
29
33
|
export declare function serverSyncSuccess(options?: {
|
package/dist/runtime/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as
|
|
1
|
+
import { c as h } from "../chunks/types-Dy4rYb2N.js";
|
|
2
2
|
const d = (r, e) => new Response(JSON.stringify(r), {
|
|
3
3
|
status: e,
|
|
4
4
|
headers: { "Content-Type": "application/json" }
|
|
@@ -11,99 +11,99 @@ const d = (r, e) => new Response(JSON.stringify(r), {
|
|
|
11
11
|
notConfigured: (r) => d({ error: `${r} handler not configured` }, 501),
|
|
12
12
|
serverError: (r) => d({ error: r instanceof Error ? r.message : "Internal server error" }, 500)
|
|
13
13
|
};
|
|
14
|
-
function
|
|
14
|
+
function p() {
|
|
15
15
|
return {
|
|
16
16
|
create: {
|
|
17
17
|
guard: (r) => !!r.create,
|
|
18
|
-
execute: (r, e) => e.create(r.data),
|
|
18
|
+
execute: (r, e, s) => e.create(r.data, s),
|
|
19
19
|
toResult: (r, e) => e.success === !0 ? { id: r.id, status: "success", newId: e.newId } : { id: r.id, status: "error", error: e.error },
|
|
20
20
|
notConfiguredError: "Create handler not configured"
|
|
21
21
|
},
|
|
22
22
|
update: {
|
|
23
23
|
guard: (r) => !!r.update,
|
|
24
|
-
execute: (r, e) => e.update(r.id, r.data),
|
|
24
|
+
execute: (r, e, s) => e.update(r.id, r.data, s),
|
|
25
25
|
toResult: (r, e) => e.success === !0 ? { id: r.id, status: "success" } : { id: r.id, status: "error", error: e.error },
|
|
26
26
|
notConfiguredError: "Update handler not configured"
|
|
27
27
|
},
|
|
28
28
|
delete: {
|
|
29
29
|
guard: (r) => !!r.delete,
|
|
30
|
-
execute: (r, e) => e.delete(r.id, r.data),
|
|
30
|
+
execute: (r, e, s) => e.delete(r.id, r.data, s),
|
|
31
31
|
toResult: (r, e) => e.success === !0 ? { id: r.id, status: "success" } : { id: r.id, status: "error", error: e.error },
|
|
32
32
|
notConfiguredError: "Delete handler not configured"
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
function
|
|
36
|
+
function y(r, e) {
|
|
37
37
|
if (!e) return { valid: !0, data: r };
|
|
38
|
-
const
|
|
39
|
-
return
|
|
38
|
+
const s = e.safeParse(r);
|
|
39
|
+
return s.success === !0 ? { valid: !0, data: s.data } : { valid: !1, error: s.error.message };
|
|
40
40
|
}
|
|
41
|
-
async function
|
|
42
|
-
const n =
|
|
41
|
+
async function v(r, e, s) {
|
|
42
|
+
const n = p()[r.type];
|
|
43
43
|
if (!n)
|
|
44
44
|
return { id: r.id, status: "error", error: `Unknown change type: ${r.type}` };
|
|
45
45
|
if (!n.guard(e))
|
|
46
46
|
return { id: r.id, status: "error", error: n.notConfiguredError };
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
return { id: r.id, status: "error", error: `Validation failed: ${
|
|
47
|
+
const i = y(r.data, e.schema);
|
|
48
|
+
if (i.valid === !1)
|
|
49
|
+
return { id: r.id, status: "error", error: `Validation failed: ${i.error}` };
|
|
50
50
|
try {
|
|
51
|
-
const
|
|
52
|
-
return n.toResult(r,
|
|
53
|
-
} catch (
|
|
51
|
+
const o = await n.execute({ ...r, data: i.data }, e, s);
|
|
52
|
+
return n.toResult(r, o);
|
|
53
|
+
} catch (o) {
|
|
54
54
|
return {
|
|
55
55
|
id: r.id,
|
|
56
56
|
status: "error",
|
|
57
|
-
error:
|
|
57
|
+
error: o instanceof Error ? o.message : "Unknown error"
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
function
|
|
61
|
+
function m(r) {
|
|
62
62
|
return { success: !0, ...r };
|
|
63
63
|
}
|
|
64
|
-
function
|
|
64
|
+
function C(r) {
|
|
65
65
|
return { success: !1, error: r };
|
|
66
66
|
}
|
|
67
|
-
function
|
|
68
|
-
const e = async (
|
|
67
|
+
function E(r) {
|
|
68
|
+
const e = async (o, t) => {
|
|
69
69
|
if (!r.fetch) throw new Error("Fetch handler not configured");
|
|
70
|
-
return r.fetch(
|
|
71
|
-
},
|
|
72
|
-
const
|
|
73
|
-
return
|
|
74
|
-
},
|
|
70
|
+
return r.fetch(o, t);
|
|
71
|
+
}, s = async (o, t) => Promise.all(o.map((u) => v(u, r, t))), f = async (o, t) => {
|
|
72
|
+
const u = await s(o, t);
|
|
73
|
+
return h(u);
|
|
74
|
+
}, n = async (o) => {
|
|
75
75
|
let t;
|
|
76
76
|
try {
|
|
77
|
-
t = await
|
|
77
|
+
t = await o.json();
|
|
78
78
|
} catch {
|
|
79
79
|
return a.invalidJson();
|
|
80
80
|
}
|
|
81
81
|
if (!t.query && !t.changes)
|
|
82
82
|
return a.invalidPayload();
|
|
83
|
-
const c = {};
|
|
83
|
+
const u = { body: t }, c = {};
|
|
84
84
|
if (t.query !== void 0) {
|
|
85
85
|
if (!r.fetch) return a.notConfigured("Fetch");
|
|
86
|
-
const l =
|
|
86
|
+
const l = y(t.query, r.querySchema);
|
|
87
87
|
if (l.valid === !1) return a.validationError(l.error);
|
|
88
|
-
c.results = await e(l.data);
|
|
88
|
+
c.results = await e(l.data, u);
|
|
89
89
|
}
|
|
90
90
|
if (t.changes !== void 0) {
|
|
91
91
|
if (!Array.isArray(t.changes)) return a.invalidPayload();
|
|
92
|
-
c.syncResults = await
|
|
92
|
+
c.syncResults = await s(t.changes, u);
|
|
93
93
|
}
|
|
94
94
|
return a.success(c);
|
|
95
95
|
};
|
|
96
96
|
return {
|
|
97
|
-
handler: async (
|
|
97
|
+
handler: async (o) => {
|
|
98
98
|
try {
|
|
99
|
-
return
|
|
99
|
+
return o.method !== "POST" ? a.methodNotAllowed() : await n(o);
|
|
100
100
|
} catch (t) {
|
|
101
101
|
return a.serverError(t);
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
104
|
fetchItems: e,
|
|
105
|
-
processChanges:
|
|
106
|
-
processChangesWithStats:
|
|
105
|
+
processChanges: s,
|
|
106
|
+
processChangesWithStats: f,
|
|
107
107
|
handlers: {
|
|
108
108
|
fetch: r.fetch,
|
|
109
109
|
create: r.create,
|
|
@@ -113,9 +113,9 @@ function C(r) {
|
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
export {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
116
|
+
h as categorizeResults,
|
|
117
|
+
E as createSyncServer,
|
|
118
|
+
C as serverSyncError,
|
|
119
|
+
m as serverSyncSuccess
|
|
120
120
|
};
|
|
121
121
|
//# sourceMappingURL=server.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sources":["../../src/runtime/server.ts"],"sourcesContent":["import type { Change, SyncResult } from \"../types\";\nimport {\n type SyncHandlerResult,\n type SyncBatchResult,\n type Schema,\n type SyncRequestBody,\n type SyncResponseBody,\n categorizeResults,\n} from \"./types\";\n\n// Re-export shared types for server module consumers\nexport type { SyncHandlerResult, SyncBatchResult, Schema, SyncRequestBody, SyncResponseBody };\nexport { categorizeResults };\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ServerFetchHandler<T, Q> = (query: Q) => Promise<T[]> | T[];\nexport type ServerCreateHandler<T> = (data: T) => Promise<SyncHandlerResult> | SyncHandlerResult;\nexport type ServerUpdateHandler<T> = (\n id: string,\n data: T,\n) => Promise<SyncHandlerResult> | SyncHandlerResult;\nexport type ServerDeleteHandler<T> = (\n id: string,\n data: T,\n) => Promise<SyncHandlerResult> | SyncHandlerResult;\n\nexport type ServerSyncHandlerConfig<T, Q = unknown> = {\n schema?: Schema<T>;\n querySchema?: Schema<Q>;\n fetch?: ServerFetchHandler<T, Q>;\n create?: ServerCreateHandler<T>;\n update?: ServerUpdateHandler<T>;\n delete?: ServerDeleteHandler<T>;\n};\n\nexport type ServerSyncHandler<T, Q = unknown> = {\n handler: (request: Request) => Promise<Response>;\n fetchItems: (query: Q) => Promise<T[]>;\n processChanges: (changes: Change<T>[]) => Promise<SyncResult[]>;\n processChangesWithStats: (changes: Change<T>[]) => Promise<SyncBatchResult>;\n handlers: {\n fetch?: ServerFetchHandler<T, Q>;\n create?: ServerCreateHandler<T>;\n update?: ServerUpdateHandler<T>;\n delete?: ServerDeleteHandler<T>;\n };\n};\n\n// ============================================================================\n// Response Helpers\n// ============================================================================\n\nconst jsonResponse = (body: unknown, status: number): Response =>\n new Response(JSON.stringify(body), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n\nconst responses = {\n success: (data: unknown) => jsonResponse(data, 200),\n methodNotAllowed: () => jsonResponse({ error: \"Method not allowed. Use POST.\" }, 405),\n invalidJson: () => jsonResponse({ error: \"Invalid JSON body\" }, 400),\n invalidPayload: () =>\n jsonResponse({ error: \"Request body must contain 'query' and/or 'changes'\" }, 400),\n validationError: (message: string) =>\n jsonResponse({ error: `Validation error: ${message}` }, 400),\n notConfigured: (handler: string) =>\n jsonResponse({ error: `${handler} handler not configured` }, 501),\n serverError: (error: unknown) =>\n jsonResponse({ error: error instanceof Error ? error.message : \"Internal server error\" }, 500),\n} as const;\n\n// ============================================================================\n// Change Processing\n// ============================================================================\n\ntype ChangeProcessor<T, Q> = {\n guard: (config: ServerSyncHandlerConfig<T, Q>) => boolean;\n execute: (\n change: Change<T>,\n config: ServerSyncHandlerConfig<T, Q>,\n ) => Promise<SyncHandlerResult> | SyncHandlerResult;\n toResult: (change: Change<T>, result: SyncHandlerResult) => SyncResult;\n notConfiguredError: string;\n};\n\nfunction createChangeProcessors<T, Q>(): Record<string, ChangeProcessor<T, Q>> {\n return {\n create: {\n guard: (config) => !!config.create,\n execute: (change, config) => config.create!(change.data),\n toResult: (change, result) =>\n result.success === true\n ? { id: change.id, status: \"success\" as const, newId: result.newId }\n : { id: change.id, status: \"error\" as const, error: result.error },\n notConfiguredError: \"Create handler not configured\",\n },\n\n update: {\n guard: (config) => !!config.update,\n execute: (change, config) => config.update!(change.id, change.data),\n toResult: (change, result) =>\n result.success === true\n ? { id: change.id, status: \"success\" as const }\n : { id: change.id, status: \"error\" as const, error: result.error },\n notConfiguredError: \"Update handler not configured\",\n },\n\n delete: {\n guard: (config) => !!config.delete,\n execute: (change, config) => config.delete!(change.id, change.data),\n toResult: (change, result) =>\n result.success === true\n ? { id: change.id, status: \"success\" as const }\n : { id: change.id, status: \"error\" as const, error: result.error },\n notConfiguredError: \"Delete handler not configured\",\n },\n };\n}\n\nfunction validateData<T>(\n data: unknown,\n schema?: Schema<T>,\n): { valid: true; data: T } | { valid: false; error: string } {\n if (!schema) return { valid: true, data: data as T };\n\n const result = schema.safeParse(data);\n return result.success === true\n ? { valid: true, data: result.data }\n : { valid: false, error: result.error.message };\n}\n\nasync function processServerChange<T, Q>(\n change: Change<T>,\n config: ServerSyncHandlerConfig<T, Q>,\n): Promise<SyncResult> {\n const processors = createChangeProcessors<T, Q>();\n const processor = processors[change.type];\n\n if (!processor) {\n return { id: change.id, status: \"error\", error: `Unknown change type: ${change.type}` };\n }\n\n if (!processor.guard(config)) {\n return { id: change.id, status: \"error\", error: processor.notConfiguredError };\n }\n\n const validation = validateData(change.data, config.schema);\n if (validation.valid === false) {\n return { id: change.id, status: \"error\", error: `Validation failed: ${validation.error}` };\n }\n\n try {\n const result = await processor.execute({ ...change, data: validation.data }, config);\n return processor.toResult(change, result);\n } catch (error) {\n return {\n id: change.id,\n status: \"error\",\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport function serverSyncSuccess(options?: { newId?: string }): SyncHandlerResult {\n return { success: true, ...options };\n}\n\nexport function serverSyncError(error: string): SyncHandlerResult {\n return { success: false, error };\n}\n\nexport function createSyncServer<T, Q = unknown>(\n config: ServerSyncHandlerConfig<T, Q>,\n): ServerSyncHandler<T, Q> {\n const fetchItems = async (query: Q): Promise<T[]> => {\n if (!config.fetch) throw new Error(\"Fetch handler not configured\");\n return config.fetch(query);\n };\n\n const processChanges = async (changes: Change<T>[]): Promise<SyncResult[]> => {\n return Promise.all(changes.map((change) => processServerChange(change, config)));\n };\n\n const processChangesWithStats = async (changes: Change<T>[]): Promise<SyncBatchResult> => {\n const results = await processChanges(changes);\n return categorizeResults(results);\n };\n\n const handlePost = async (request: Request): Promise<Response> => {\n let body: SyncRequestBody<T, Q>;\n try {\n body = await request.json();\n } catch {\n return responses.invalidJson();\n }\n\n if (!body.query && !body.changes) {\n return responses.invalidPayload();\n }\n\n const responseBody: SyncResponseBody<T> = {};\n\n if (body.query !== undefined) {\n if (!config.fetch) return responses.notConfigured(\"Fetch\");\n\n const validation = validateData<Q>(body.query, config.querySchema);\n if (validation.valid === false) return responses.validationError(validation.error);\n\n responseBody.results = await fetchItems(validation.data);\n }\n\n if (body.changes !== undefined) {\n if (!Array.isArray(body.changes)) return responses.invalidPayload();\n responseBody.syncResults = await processChanges(body.changes);\n }\n\n return responses.success(responseBody);\n };\n\n const handler = async (request: Request): Promise<Response> => {\n try {\n if (request.method !== \"POST\") return responses.methodNotAllowed();\n return await handlePost(request);\n } catch (error) {\n return responses.serverError(error);\n }\n };\n\n return {\n handler,\n fetchItems,\n processChanges,\n processChangesWithStats,\n handlers: {\n fetch: config.fetch,\n create: config.create,\n update: config.update,\n delete: config.delete,\n },\n };\n}\n"],"names":["jsonResponse","body","status","responses","data","message","handler","error","createChangeProcessors","config","change","result","validateData","schema","processServerChange","processor","validation","serverSyncSuccess","options","serverSyncError","createSyncServer","fetchItems","query","processChanges","changes","processChangesWithStats","results","categorizeResults","handlePost","request","responseBody"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sources":["../../src/runtime/server.ts"],"sourcesContent":["import type { Change, SyncResult } from \"../types\";\nimport {\n type SyncHandlerResult,\n type SyncBatchResult,\n type Schema,\n type SyncRequestBody,\n type SyncResponseBody,\n categorizeResults,\n} from \"./types\";\n\n// Re-export shared types for server module consumers\nexport type { SyncHandlerResult, SyncBatchResult, Schema, SyncRequestBody, SyncResponseBody };\nexport { categorizeResults };\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Context passed to all handlers containing the parsed request body */\nexport type ServerHandlerContext<T, Q = unknown> = {\n body: SyncRequestBody<T, Q>;\n};\n\nexport type ServerFetchHandler<T, Q> = (\n query: Q,\n ctx: ServerHandlerContext<T, Q>,\n) => Promise<T[]> | T[];\nexport type ServerCreateHandler<T, Q = unknown> = (\n data: T,\n ctx: ServerHandlerContext<T, Q>,\n) => Promise<SyncHandlerResult> | SyncHandlerResult;\nexport type ServerUpdateHandler<T, Q = unknown> = (\n id: string,\n data: T,\n ctx: ServerHandlerContext<T, Q>,\n) => Promise<SyncHandlerResult> | SyncHandlerResult;\nexport type ServerDeleteHandler<T, Q = unknown> = (\n id: string,\n data: T,\n ctx: ServerHandlerContext<T, Q>,\n) => Promise<SyncHandlerResult> | SyncHandlerResult;\n\nexport type ServerSyncHandlerConfig<T, Q = unknown> = {\n schema?: Schema<T>;\n querySchema?: Schema<Q>;\n fetch?: ServerFetchHandler<T, Q>;\n create?: ServerCreateHandler<T, Q>;\n update?: ServerUpdateHandler<T, Q>;\n delete?: ServerDeleteHandler<T, Q>;\n};\n\nexport type ServerSyncHandler<T, Q = unknown> = {\n handler: (request: Request) => Promise<Response>;\n fetchItems: (query: Q, ctx: ServerHandlerContext<T, Q>) => Promise<T[]>;\n processChanges: (changes: Change<T>[], ctx: ServerHandlerContext<T, Q>) => Promise<SyncResult[]>;\n processChangesWithStats: (\n changes: Change<T>[],\n ctx: ServerHandlerContext<T, Q>,\n ) => Promise<SyncBatchResult>;\n handlers: {\n fetch?: ServerFetchHandler<T, Q>;\n create?: ServerCreateHandler<T, Q>;\n update?: ServerUpdateHandler<T, Q>;\n delete?: ServerDeleteHandler<T, Q>;\n };\n};\n\n// ============================================================================\n// Response Helpers\n// ============================================================================\n\nconst jsonResponse = (body: unknown, status: number): Response =>\n new Response(JSON.stringify(body), {\n status,\n headers: { \"Content-Type\": \"application/json\" },\n });\n\nconst responses = {\n success: (data: unknown) => jsonResponse(data, 200),\n methodNotAllowed: () => jsonResponse({ error: \"Method not allowed. Use POST.\" }, 405),\n invalidJson: () => jsonResponse({ error: \"Invalid JSON body\" }, 400),\n invalidPayload: () =>\n jsonResponse({ error: \"Request body must contain 'query' and/or 'changes'\" }, 400),\n validationError: (message: string) =>\n jsonResponse({ error: `Validation error: ${message}` }, 400),\n notConfigured: (handler: string) =>\n jsonResponse({ error: `${handler} handler not configured` }, 501),\n serverError: (error: unknown) =>\n jsonResponse({ error: error instanceof Error ? error.message : \"Internal server error\" }, 500),\n} as const;\n\n// ============================================================================\n// Change Processing\n// ============================================================================\n\ntype ChangeProcessor<T, Q> = {\n guard: (config: ServerSyncHandlerConfig<T, Q>) => boolean;\n execute: (\n change: Change<T>,\n config: ServerSyncHandlerConfig<T, Q>,\n ctx: ServerHandlerContext<T, Q>,\n ) => Promise<SyncHandlerResult> | SyncHandlerResult;\n toResult: (change: Change<T>, result: SyncHandlerResult) => SyncResult;\n notConfiguredError: string;\n};\n\nfunction createChangeProcessors<T, Q>(): Record<string, ChangeProcessor<T, Q>> {\n return {\n create: {\n guard: (config) => !!config.create,\n execute: (change, config, ctx) => config.create!(change.data, ctx),\n toResult: (change, result) =>\n result.success === true\n ? { id: change.id, status: \"success\" as const, newId: result.newId }\n : { id: change.id, status: \"error\" as const, error: result.error },\n notConfiguredError: \"Create handler not configured\",\n },\n\n update: {\n guard: (config) => !!config.update,\n execute: (change, config, ctx) => config.update!(change.id, change.data, ctx),\n toResult: (change, result) =>\n result.success === true\n ? { id: change.id, status: \"success\" as const }\n : { id: change.id, status: \"error\" as const, error: result.error },\n notConfiguredError: \"Update handler not configured\",\n },\n\n delete: {\n guard: (config) => !!config.delete,\n execute: (change, config, ctx) => config.delete!(change.id, change.data, ctx),\n toResult: (change, result) =>\n result.success === true\n ? { id: change.id, status: \"success\" as const }\n : { id: change.id, status: \"error\" as const, error: result.error },\n notConfiguredError: \"Delete handler not configured\",\n },\n };\n}\n\nfunction validateData<T>(\n data: unknown,\n schema?: Schema<T>,\n): { valid: true; data: T } | { valid: false; error: string } {\n if (!schema) return { valid: true, data: data as T };\n\n const result = schema.safeParse(data);\n return result.success === true\n ? { valid: true, data: result.data }\n : { valid: false, error: result.error.message };\n}\n\nasync function processServerChange<T, Q>(\n change: Change<T>,\n config: ServerSyncHandlerConfig<T, Q>,\n ctx: ServerHandlerContext<T, Q>,\n): Promise<SyncResult> {\n const processors = createChangeProcessors<T, Q>();\n const processor = processors[change.type];\n\n if (!processor) {\n return { id: change.id, status: \"error\", error: `Unknown change type: ${change.type}` };\n }\n\n if (!processor.guard(config)) {\n return { id: change.id, status: \"error\", error: processor.notConfiguredError };\n }\n\n const validation = validateData(change.data, config.schema);\n if (validation.valid === false) {\n return { id: change.id, status: \"error\", error: `Validation failed: ${validation.error}` };\n }\n\n try {\n const result = await processor.execute({ ...change, data: validation.data }, config, ctx);\n return processor.toResult(change, result);\n } catch (error) {\n return {\n id: change.id,\n status: \"error\",\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport function serverSyncSuccess(options?: { newId?: string }): SyncHandlerResult {\n return { success: true, ...options };\n}\n\nexport function serverSyncError(error: string): SyncHandlerResult {\n return { success: false, error };\n}\n\nexport function createSyncServer<T, Q = unknown>(\n config: ServerSyncHandlerConfig<T, Q>,\n): ServerSyncHandler<T, Q> {\n const fetchItems = async (query: Q, ctx: ServerHandlerContext<T, Q>): Promise<T[]> => {\n if (!config.fetch) throw new Error(\"Fetch handler not configured\");\n return config.fetch(query, ctx);\n };\n\n const processChanges = async (\n changes: Change<T>[],\n ctx: ServerHandlerContext<T, Q>,\n ): Promise<SyncResult[]> => {\n return Promise.all(changes.map((change) => processServerChange(change, config, ctx)));\n };\n\n const processChangesWithStats = async (\n changes: Change<T>[],\n ctx: ServerHandlerContext<T, Q>,\n ): Promise<SyncBatchResult> => {\n const results = await processChanges(changes, ctx);\n return categorizeResults(results);\n };\n\n const handlePost = async (request: Request): Promise<Response> => {\n let body: SyncRequestBody<T, Q>;\n try {\n body = await request.json();\n } catch {\n return responses.invalidJson();\n }\n\n if (!body.query && !body.changes) {\n return responses.invalidPayload();\n }\n\n const ctx: ServerHandlerContext<T, Q> = { body };\n const responseBody: SyncResponseBody<T> = {};\n\n if (body.query !== undefined) {\n if (!config.fetch) return responses.notConfigured(\"Fetch\");\n\n const validation = validateData<Q>(body.query, config.querySchema);\n if (validation.valid === false) return responses.validationError(validation.error);\n\n responseBody.results = await fetchItems(validation.data, ctx);\n }\n\n if (body.changes !== undefined) {\n if (!Array.isArray(body.changes)) return responses.invalidPayload();\n responseBody.syncResults = await processChanges(body.changes, ctx);\n }\n\n return responses.success(responseBody);\n };\n\n const handler = async (request: Request): Promise<Response> => {\n try {\n if (request.method !== \"POST\") return responses.methodNotAllowed();\n return await handlePost(request);\n } catch (error) {\n return responses.serverError(error);\n }\n };\n\n return {\n handler,\n fetchItems,\n processChanges,\n processChangesWithStats,\n handlers: {\n fetch: config.fetch,\n create: config.create,\n update: config.update,\n delete: config.delete,\n },\n };\n}\n"],"names":["jsonResponse","body","status","responses","data","message","handler","error","createChangeProcessors","config","change","ctx","result","validateData","schema","processServerChange","processor","validation","serverSyncSuccess","options","serverSyncError","createSyncServer","fetchItems","query","processChanges","changes","processChangesWithStats","results","categorizeResults","handlePost","request","responseBody"],"mappings":"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"}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -54,6 +54,8 @@ export declare function categorizeResults(results: SyncResult[]): SyncBatchResul
|
|
|
54
54
|
* Request body for the unified POST endpoint
|
|
55
55
|
*/
|
|
56
56
|
export type SyncRequestBody<T, Q = unknown> = {
|
|
57
|
+
/** Optional scope identifier for selecting storage on the backend */
|
|
58
|
+
scope?: string;
|
|
57
59
|
/** Query parameters for fetching items */
|
|
58
60
|
query?: Q;
|
|
59
61
|
/** Changes to sync */
|
package/dist/sync-queue.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { c as p } from "./types-Dy4rYb2N.js";
|
|
2
|
-
function f() {
|
|
3
|
-
return {
|
|
4
|
-
create: {
|
|
5
|
-
guard: (r) => !!r.create,
|
|
6
|
-
execute: (r, e, o) => e.create(r.data, o),
|
|
7
|
-
toResult: (r, e) => e.success === !0 ? { id: r.id, status: "success", newId: e.newId } : { id: r.id, status: "error", error: e.error }
|
|
8
|
-
},
|
|
9
|
-
update: {
|
|
10
|
-
guard: (r) => !!r.update,
|
|
11
|
-
execute: (r, e, o) => e.update(r.id, r.data, o),
|
|
12
|
-
toResult: (r, e) => e.success === !0 ? { id: r.id, status: "success" } : { id: r.id, status: "error", error: e.error }
|
|
13
|
-
},
|
|
14
|
-
delete: {
|
|
15
|
-
guard: (r) => !!r.delete,
|
|
16
|
-
execute: (r, e, o) => e.delete(r.id, r.data, o),
|
|
17
|
-
toResult: (r, e) => e.success === !0 ? { id: r.id, status: "success" } : { id: r.id, status: "error", error: e.error }
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
async function l(r, e, o) {
|
|
22
|
-
if (o.aborted)
|
|
23
|
-
return { id: r.id, status: "error", error: "Operation aborted" };
|
|
24
|
-
const n = f()[r.type];
|
|
25
|
-
if (!n)
|
|
26
|
-
return { id: r.id, status: "error", error: `Unknown change type: ${r.type}` };
|
|
27
|
-
if (!n.guard(e))
|
|
28
|
-
return { id: r.id, status: "success" };
|
|
29
|
-
try {
|
|
30
|
-
const t = await n.execute(r, e, o);
|
|
31
|
-
return n.toResult(r, t);
|
|
32
|
-
} catch (t) {
|
|
33
|
-
return {
|
|
34
|
-
id: r.id,
|
|
35
|
-
status: "error",
|
|
36
|
-
error: t instanceof Error ? t.message : "Unknown error"
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function w(r) {
|
|
41
|
-
return {
|
|
42
|
-
onSync: async (o, c) => Promise.all(o.map((n) => l(n, r, c))),
|
|
43
|
-
handlers: { create: r.create, update: r.update, delete: r.delete }
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
function S(r) {
|
|
47
|
-
const { onSync: e, handlers: o } = w(r);
|
|
48
|
-
return { onSync: e, onSyncWithStats: async (n, t) => {
|
|
49
|
-
const a = await e(n, t);
|
|
50
|
-
return p(a);
|
|
51
|
-
}, handlers: o };
|
|
52
|
-
}
|
|
53
|
-
function E(r) {
|
|
54
|
-
return { success: !0, ...r };
|
|
55
|
-
}
|
|
56
|
-
function b(r) {
|
|
57
|
-
return { success: !1, error: r };
|
|
58
|
-
}
|
|
59
|
-
function h(r) {
|
|
60
|
-
const e = typeof r == "string" ? r : r.endpoint, o = typeof r == "string" ? {} : r.headers ?? {};
|
|
61
|
-
return { onFetch: async (t, a) => {
|
|
62
|
-
if (a.aborted)
|
|
63
|
-
throw new Error("Operation aborted");
|
|
64
|
-
try {
|
|
65
|
-
const s = { query: t }, u = await fetch(e, {
|
|
66
|
-
method: "POST",
|
|
67
|
-
headers: { "Content-Type": "application/json", ...o },
|
|
68
|
-
body: JSON.stringify(s),
|
|
69
|
-
signal: a
|
|
70
|
-
});
|
|
71
|
-
if (!u.ok) {
|
|
72
|
-
let i = "Fetch request failed";
|
|
73
|
-
try {
|
|
74
|
-
const d = await u.json();
|
|
75
|
-
d.error && (i = d.error);
|
|
76
|
-
} catch {
|
|
77
|
-
}
|
|
78
|
-
throw new Error(i);
|
|
79
|
-
}
|
|
80
|
-
return (await u.json()).results ?? [];
|
|
81
|
-
} catch (s) {
|
|
82
|
-
throw s instanceof Error && s.name === "AbortError" ? new Error("Operation aborted") : s;
|
|
83
|
-
}
|
|
84
|
-
}, onSync: async (t, a) => {
|
|
85
|
-
if (a.aborted)
|
|
86
|
-
return t.map((s) => ({
|
|
87
|
-
id: s.id,
|
|
88
|
-
status: "error",
|
|
89
|
-
error: "Operation aborted"
|
|
90
|
-
}));
|
|
91
|
-
try {
|
|
92
|
-
const s = { changes: t }, u = await fetch(e, {
|
|
93
|
-
method: "POST",
|
|
94
|
-
headers: { "Content-Type": "application/json", ...o },
|
|
95
|
-
body: JSON.stringify(s),
|
|
96
|
-
signal: a
|
|
97
|
-
});
|
|
98
|
-
if (!u.ok) {
|
|
99
|
-
let i = "Sync request failed";
|
|
100
|
-
try {
|
|
101
|
-
const d = await u.json();
|
|
102
|
-
d.error && (i = d.error);
|
|
103
|
-
} catch {
|
|
104
|
-
}
|
|
105
|
-
return t.map((d) => ({ id: d.id, status: "error", error: i }));
|
|
106
|
-
}
|
|
107
|
-
return (await u.json()).syncResults ?? t.map((i) => ({
|
|
108
|
-
id: i.id,
|
|
109
|
-
status: "error",
|
|
110
|
-
error: "No sync results returned"
|
|
111
|
-
}));
|
|
112
|
-
} catch (s) {
|
|
113
|
-
const u = s instanceof Error && s.name === "AbortError" ? "Operation aborted" : s instanceof Error ? s.message : "Unknown error";
|
|
114
|
-
return t.map((y) => ({ id: y.id, status: "error", error: u }));
|
|
115
|
-
}
|
|
116
|
-
} };
|
|
117
|
-
}
|
|
118
|
-
async function O(r) {
|
|
119
|
-
const { fetch: e, parseResponse: o, parseError: c } = r, n = (t) => typeof c == "function" ? c(t) : typeof c == "string" ? c : t instanceof Error ? t.message : "Request failed";
|
|
120
|
-
try {
|
|
121
|
-
const t = await e;
|
|
122
|
-
if (!t.ok) {
|
|
123
|
-
let a = new Error("Request failed");
|
|
124
|
-
try {
|
|
125
|
-
const s = await t.json();
|
|
126
|
-
s.message ? a = new Error(s.message) : s.error && (a = new Error(s.error));
|
|
127
|
-
} catch {
|
|
128
|
-
}
|
|
129
|
-
return { success: !1, error: n(a) };
|
|
130
|
-
}
|
|
131
|
-
return o ? { success: !0, ...await o(t) } : { success: !0 };
|
|
132
|
-
} catch (t) {
|
|
133
|
-
return t instanceof Error && t.name === "AbortError" ? { success: !1, error: "Operation aborted" } : { success: !1, error: n(t) };
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
export {
|
|
137
|
-
S as a,
|
|
138
|
-
h as b,
|
|
139
|
-
w as c,
|
|
140
|
-
b as d,
|
|
141
|
-
O as f,
|
|
142
|
-
E as s
|
|
143
|
-
};
|
|
144
|
-
//# sourceMappingURL=client-VrsFvEIA.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client-VrsFvEIA.js","sources":["../../src/runtime/client.ts"],"sourcesContent":["import type { Change, SyncResult } from \"../types\";\nimport {\n type SyncHandlerResult,\n type SyncBatchResult,\n type SyncRequestBody,\n type SyncResponseBody,\n categorizeResults,\n} from \"./types\";\n\nexport type { SyncHandlerResult, SyncBatchResult };\nexport { categorizeResults };\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type CreateHandler<T> = (data: T, signal: AbortSignal) => Promise<SyncHandlerResult>;\nexport type UpdateHandler<T> = (\n id: string,\n data: T,\n signal: AbortSignal,\n) => Promise<SyncHandlerResult>;\nexport type DeleteHandler<T> = (\n id: string,\n data: T,\n signal: AbortSignal,\n) => Promise<SyncHandlerResult>;\n\nexport type SyncBuilderConfig<T> = {\n create?: CreateHandler<T>;\n update?: UpdateHandler<T>;\n delete?: DeleteHandler<T>;\n};\n\nexport type SyncBuilder<T> = {\n onSync: (changes: Change<T>[], signal: AbortSignal) => Promise<SyncResult[]>;\n handlers: {\n create?: CreateHandler<T>;\n update?: UpdateHandler<T>;\n delete?: DeleteHandler<T>;\n };\n};\n\nexport type FetchToSyncResultOptions = {\n fetch: Promise<Response>;\n parseResponse?: (response: Response) => Promise<{ newId?: string }>;\n parseError?: string | ((error: unknown) => string);\n};\n\n// ============================================================================\n// Change Processing\n// ============================================================================\n\ntype ChangeProcessor<T> = {\n guard: (config: SyncBuilderConfig<T>) => boolean;\n execute: (\n change: Change<T>,\n config: SyncBuilderConfig<T>,\n signal: AbortSignal,\n ) => Promise<SyncHandlerResult>;\n toResult: (change: Change<T>, result: SyncHandlerResult) => SyncResult;\n};\n\nfunction createChangeProcessors<T>(): Record<string, ChangeProcessor<T>> {\n return {\n create: {\n guard: (config) => !!config.create,\n execute: (change, config, signal) => config.create!(change.data, signal),\n toResult: (change, result) =>\n result.success === true\n ? { id: change.id, status: \"success\" as const, newId: result.newId }\n : { id: change.id, status: \"error\" as const, error: result.error },\n },\n\n update: {\n guard: (config) => !!config.update,\n execute: (change, config, signal) => config.update!(change.id, change.data, signal),\n toResult: (change, result) =>\n result.success === true\n ? { id: change.id, status: \"success\" as const }\n : { id: change.id, status: \"error\" as const, error: result.error },\n },\n\n delete: {\n guard: (config) => !!config.delete,\n execute: (change, config, signal) => config.delete!(change.id, change.data, signal),\n toResult: (change, result) =>\n result.success === true\n ? { id: change.id, status: \"success\" as const }\n : { id: change.id, status: \"error\" as const, error: result.error },\n },\n };\n}\n\nasync function processChange<T>(\n change: Change<T>,\n config: SyncBuilderConfig<T>,\n signal: AbortSignal,\n): Promise<SyncResult> {\n if (signal.aborted) {\n return { id: change.id, status: \"error\", error: \"Operation aborted\" };\n }\n\n const processors = createChangeProcessors<T>();\n const processor = processors[change.type];\n\n if (!processor) {\n return { id: change.id, status: \"error\", error: `Unknown change type: ${change.type}` };\n }\n\n // If handler not configured, treat as success (offline-first support)\n if (!processor.guard(config)) {\n return { id: change.id, status: \"success\" };\n }\n\n try {\n const result = await processor.execute(change, config, signal);\n return processor.toResult(change, result);\n } catch (error) {\n return {\n id: change.id,\n status: \"error\",\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\nexport function createSyncClient<T>(config: SyncBuilderConfig<T>): SyncBuilder<T> {\n const onSync = async (changes: Change<T>[], signal: AbortSignal): Promise<SyncResult[]> => {\n return Promise.all(changes.map((change) => processChange(change, config, signal)));\n };\n\n return {\n onSync,\n handlers: { create: config.create, update: config.update, delete: config.delete },\n };\n}\n\nexport function createSyncClientWithStats<T>(config: SyncBuilderConfig<T>): {\n onSync: (changes: Change<T>[], signal: AbortSignal) => Promise<SyncResult[]>;\n onSyncWithStats: (changes: Change<T>[], signal: AbortSignal) => Promise<SyncBatchResult>;\n handlers: { create?: CreateHandler<T>; update?: UpdateHandler<T>; delete?: DeleteHandler<T> };\n} {\n const { onSync, handlers } = createSyncClient(config);\n\n const onSyncWithStats = async (\n changes: Change<T>[],\n signal: AbortSignal,\n ): Promise<SyncBatchResult> => {\n const results = await onSync(changes, signal);\n return categorizeResults(results);\n };\n\n return { onSync, onSyncWithStats, handlers };\n}\n\nexport function syncSuccess(options?: { newId?: string }): SyncHandlerResult {\n return { success: true, ...options };\n}\n\nexport function syncError(error: string): SyncHandlerResult {\n return { success: false, error };\n}\n\nexport type EndpointSyncClientConfig = {\n endpoint: string;\n headers?: Record<string, string>;\n};\n\nexport type EndpointSyncClient<T, Q = unknown> = {\n onFetch: (query: Q, signal: AbortSignal) => Promise<T[]>;\n onSync: (changes: Change<T>[], signal: AbortSignal) => Promise<SyncResult[]>;\n};\n\nexport function createSyncClientFromEndpoint<T, Q = unknown>(\n config: string | EndpointSyncClientConfig,\n): EndpointSyncClient<T, Q> {\n const endpoint = typeof config === \"string\" ? config : config.endpoint;\n const headers = typeof config === \"string\" ? {} : (config.headers ?? {});\n\n const onFetch = async (query: Q, signal: AbortSignal): Promise<T[]> => {\n if (signal.aborted) {\n throw new Error(\"Operation aborted\");\n }\n\n try {\n const body: SyncRequestBody<T, Q> = { query };\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...headers },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!response.ok) {\n let errorMsg = \"Fetch request failed\";\n try {\n const errorBody = await response.json();\n if (errorBody.error) errorMsg = errorBody.error;\n } catch {\n // Ignore JSON parse errors\n }\n throw new Error(errorMsg);\n }\n\n const responseBody: SyncResponseBody<T> = await response.json();\n return responseBody.results ?? [];\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(\"Operation aborted\");\n }\n throw error;\n }\n };\n\n const onSync = async (changes: Change<T>[], signal: AbortSignal): Promise<SyncResult[]> => {\n if (signal.aborted) {\n return changes.map((c) => ({\n id: c.id,\n status: \"error\" as const,\n error: \"Operation aborted\",\n }));\n }\n\n try {\n const body: SyncRequestBody<T, Q> = { changes };\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", ...headers },\n body: JSON.stringify(body),\n signal,\n });\n\n if (!response.ok) {\n let errorMsg = \"Sync request failed\";\n try {\n const errorBody = await response.json();\n if (errorBody.error) errorMsg = errorBody.error;\n } catch {\n // Ignore JSON parse errors\n }\n return changes.map((c) => ({ id: c.id, status: \"error\" as const, error: errorMsg }));\n }\n\n const responseBody: SyncResponseBody<T> = await response.json();\n return (\n responseBody.syncResults ??\n changes.map((c) => ({\n id: c.id,\n status: \"error\" as const,\n error: \"No sync results returned\",\n }))\n );\n } catch (error) {\n const errorMsg =\n error instanceof Error && error.name === \"AbortError\"\n ? \"Operation aborted\"\n : error instanceof Error\n ? error.message\n : \"Unknown error\";\n return changes.map((c) => ({ id: c.id, status: \"error\" as const, error: errorMsg }));\n }\n };\n\n return { onFetch, onSync };\n}\n\nexport async function fetchToSyncResult(\n options: FetchToSyncResultOptions,\n): Promise<SyncHandlerResult> {\n const { fetch: fetchPromise, parseResponse, parseError } = options;\n\n const getErrorMessage = (error: unknown): string => {\n if (typeof parseError === \"function\") return parseError(error);\n if (typeof parseError === \"string\") return parseError;\n return error instanceof Error ? error.message : \"Request failed\";\n };\n\n try {\n const response = await fetchPromise;\n\n if (!response.ok) {\n let error: unknown = new Error(\"Request failed\");\n try {\n const body = await response.json();\n if (body.message) error = new Error(body.message);\n else if (body.error) error = new Error(body.error);\n } catch {\n // Ignore JSON parse errors\n }\n return { success: false, error: getErrorMessage(error) };\n }\n\n if (parseResponse) {\n const result = await parseResponse(response);\n return { success: true, ...result };\n }\n\n return { success: true };\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n return { success: false, error: \"Operation aborted\" };\n }\n return { success: false, error: getErrorMessage(error) };\n }\n}\n"],"names":["createChangeProcessors","config","change","signal","result","processChange","processor","error","createSyncClient","changes","createSyncClientWithStats","onSync","handlers","results","categorizeResults","syncSuccess","options","syncError","createSyncClientFromEndpoint","endpoint","headers","query","body","response","errorMsg","errorBody","c","fetchToSyncResult","fetchPromise","parseResponse","parseError","getErrorMessage"],"mappings":"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"}
|