shardwire 0.0.3 → 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 +93 -3
- package/dist/index.d.mts +81 -9
- package/dist/index.d.ts +81 -9
- package/dist/index.js +255 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +252 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -3
package/dist/index.js
CHANGED
|
@@ -30,7 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
createShardwire: () => createShardwire
|
|
33
|
+
createShardwire: () => createShardwire,
|
|
34
|
+
fromSafeParseSchema: () => fromSafeParseSchema,
|
|
35
|
+
fromZodSchema: () => fromZodSchema
|
|
34
36
|
});
|
|
35
37
|
module.exports = __toCommonJS(index_exports);
|
|
36
38
|
|
|
@@ -100,6 +102,14 @@ function stringifyEnvelope(envelope) {
|
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
// src/runtime/validation.ts
|
|
105
|
+
var PayloadValidationError = class extends Error {
|
|
106
|
+
constructor(message, details) {
|
|
107
|
+
super(message);
|
|
108
|
+
this.details = details;
|
|
109
|
+
this.name = "PayloadValidationError";
|
|
110
|
+
}
|
|
111
|
+
details;
|
|
112
|
+
};
|
|
103
113
|
function isNonEmptyString(value) {
|
|
104
114
|
return typeof value === "string" && value.trim().length > 0;
|
|
105
115
|
}
|
|
@@ -138,12 +148,30 @@ function assertConsumerOptions(options) {
|
|
|
138
148
|
if (!isNonEmptyString(options.url)) {
|
|
139
149
|
throw new Error("Consumer mode requires `url`.");
|
|
140
150
|
}
|
|
151
|
+
let parsedUrl;
|
|
152
|
+
try {
|
|
153
|
+
parsedUrl = new URL(options.url);
|
|
154
|
+
} catch {
|
|
155
|
+
throw new Error("Consumer option `url` must be a valid URL.");
|
|
156
|
+
}
|
|
157
|
+
if (parsedUrl.protocol !== "ws:" && parsedUrl.protocol !== "wss:") {
|
|
158
|
+
throw new Error("Consumer option `url` must use `ws://` or `wss://`.");
|
|
159
|
+
}
|
|
160
|
+
const isLoopbackHost = parsedUrl.hostname === "localhost" || parsedUrl.hostname === "127.0.0.1" || parsedUrl.hostname === "::1";
|
|
161
|
+
if (parsedUrl.protocol === "ws:" && !isLoopbackHost && !options.allowInsecureWs) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
"Insecure `ws://` is only allowed for loopback hosts by default. Use `wss://` or set `allowInsecureWs` to true."
|
|
164
|
+
);
|
|
165
|
+
}
|
|
141
166
|
if (!isNonEmptyString(options.secret)) {
|
|
142
167
|
throw new Error("Consumer mode requires `secret`.");
|
|
143
168
|
}
|
|
144
169
|
if (options.secretId !== void 0 && !isNonEmptyString(options.secretId)) {
|
|
145
170
|
throw new Error("Consumer option `secretId` must be a non-empty string.");
|
|
146
171
|
}
|
|
172
|
+
if (options.clientName !== void 0 && !isNonEmptyString(options.clientName)) {
|
|
173
|
+
throw new Error("Consumer option `clientName` must be a non-empty string.");
|
|
174
|
+
}
|
|
147
175
|
if (options.requestTimeoutMs !== void 0) {
|
|
148
176
|
assertPositiveNumber("requestTimeoutMs", options.requestTimeoutMs);
|
|
149
177
|
}
|
|
@@ -166,9 +194,54 @@ function assertJsonPayload(kind, name, payload) {
|
|
|
166
194
|
throw new Error(`${kind} "${name}" payload must be JSON-serializable.`);
|
|
167
195
|
}
|
|
168
196
|
}
|
|
197
|
+
function normalizeSchemaIssues(error) {
|
|
198
|
+
if (!error || typeof error !== "object") {
|
|
199
|
+
return void 0;
|
|
200
|
+
}
|
|
201
|
+
const issues = error.issues;
|
|
202
|
+
if (!Array.isArray(issues)) {
|
|
203
|
+
return void 0;
|
|
204
|
+
}
|
|
205
|
+
const normalized = issues.map((issue) => {
|
|
206
|
+
if (!issue || typeof issue !== "object") {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
const message = issue.message;
|
|
210
|
+
const rawPath = issue.path;
|
|
211
|
+
if (typeof message !== "string") {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
const path = Array.isArray(rawPath) && rawPath.length > 0 ? rawPath.map((segment) => typeof segment === "string" || typeof segment === "number" ? String(segment) : "").filter(Boolean).join(".") : "";
|
|
215
|
+
return { path, message };
|
|
216
|
+
}).filter((issue) => Boolean(issue));
|
|
217
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
218
|
+
}
|
|
219
|
+
function parsePayloadWithSchema(schema, payload, context) {
|
|
220
|
+
if (!schema) {
|
|
221
|
+
return payload;
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
return schema.parse(payload);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
const message = error instanceof Error && error.message.trim().length > 0 ? error.message : `Payload validation failed for ${context.stage} "${context.name}".`;
|
|
227
|
+
const issues = normalizeSchemaIssues(error);
|
|
228
|
+
throw new PayloadValidationError(message, {
|
|
229
|
+
...context,
|
|
230
|
+
...issues ? { issues } : {}
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
169
234
|
|
|
170
235
|
// src/consumer/index.ts
|
|
171
236
|
var DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
|
|
237
|
+
var CommandRequestError = class extends Error {
|
|
238
|
+
constructor(code, message) {
|
|
239
|
+
super(message);
|
|
240
|
+
this.code = code;
|
|
241
|
+
this.name = "CommandRequestError";
|
|
242
|
+
}
|
|
243
|
+
code;
|
|
244
|
+
};
|
|
172
245
|
function createConsumerShardwire(options) {
|
|
173
246
|
const logger = withLogger(options.logger);
|
|
174
247
|
const reconnectEnabled = options.reconnect?.enabled ?? true;
|
|
@@ -185,8 +258,12 @@ function createConsumerShardwire(options) {
|
|
|
185
258
|
let connectResolve = null;
|
|
186
259
|
let connectReject = null;
|
|
187
260
|
let authTimeoutTimer = null;
|
|
261
|
+
let currentConnectionId = null;
|
|
188
262
|
const pendingRequests = /* @__PURE__ */ new Map();
|
|
189
263
|
const eventHandlers = /* @__PURE__ */ new Map();
|
|
264
|
+
const connectedHandlers = /* @__PURE__ */ new Set();
|
|
265
|
+
const disconnectedHandlers = /* @__PURE__ */ new Set();
|
|
266
|
+
const reconnectingHandlers = /* @__PURE__ */ new Set();
|
|
190
267
|
function clearAuthTimeout() {
|
|
191
268
|
if (authTimeoutTimer) {
|
|
192
269
|
clearTimeout(authTimeoutTimer);
|
|
@@ -215,10 +292,10 @@ function createConsumerShardwire(options) {
|
|
|
215
292
|
}
|
|
216
293
|
socket.send(data);
|
|
217
294
|
}
|
|
218
|
-
function rejectAllPending(reason) {
|
|
295
|
+
function rejectAllPending(code, reason) {
|
|
219
296
|
for (const [requestId, pending] of pendingRequests.entries()) {
|
|
220
297
|
clearTimeout(pending.timer);
|
|
221
|
-
pending.reject(new
|
|
298
|
+
pending.reject(new CommandRequestError(code, reason));
|
|
222
299
|
pendingRequests.delete(requestId);
|
|
223
300
|
}
|
|
224
301
|
}
|
|
@@ -228,6 +305,13 @@ function createConsumerShardwire(options) {
|
|
|
228
305
|
}
|
|
229
306
|
const delay = getBackoffDelay(reconnectAttempts, { initialDelayMs, maxDelayMs, jitter });
|
|
230
307
|
reconnectAttempts += 1;
|
|
308
|
+
for (const handler of reconnectingHandlers) {
|
|
309
|
+
try {
|
|
310
|
+
handler({ attempt: reconnectAttempts, delayMs: delay, at: Date.now() });
|
|
311
|
+
} catch (error) {
|
|
312
|
+
logger.warn("Reconnect handler threw an error.", { error: String(error) });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
231
315
|
reconnectTimer = setTimeout(() => {
|
|
232
316
|
reconnectTimer = null;
|
|
233
317
|
void connect().catch((error) => {
|
|
@@ -266,9 +350,11 @@ function createConsumerShardwire(options) {
|
|
|
266
350
|
socket.on("open", () => {
|
|
267
351
|
reconnectAttempts = 0;
|
|
268
352
|
isAuthed = false;
|
|
353
|
+
currentConnectionId = null;
|
|
269
354
|
const hello = makeEnvelope("auth.hello", {
|
|
270
355
|
secret: options.secret,
|
|
271
|
-
secretId: options.secretId
|
|
356
|
+
secretId: options.secretId,
|
|
357
|
+
clientName: options.clientName
|
|
272
358
|
});
|
|
273
359
|
socket?.send(stringifyEnvelope(hello));
|
|
274
360
|
authTimeoutTimer = setTimeout(() => {
|
|
@@ -285,6 +371,18 @@ function createConsumerShardwire(options) {
|
|
|
285
371
|
switch (envelope.type) {
|
|
286
372
|
case "auth.ok":
|
|
287
373
|
isAuthed = true;
|
|
374
|
+
if (envelope.payload && typeof envelope.payload === "object" && "connectionId" in envelope.payload && typeof envelope.payload.connectionId === "string") {
|
|
375
|
+
currentConnectionId = envelope.payload.connectionId;
|
|
376
|
+
}
|
|
377
|
+
if (currentConnectionId) {
|
|
378
|
+
for (const handler of connectedHandlers) {
|
|
379
|
+
try {
|
|
380
|
+
handler({ connectionId: currentConnectionId, connectedAt: Date.now() });
|
|
381
|
+
} catch (error) {
|
|
382
|
+
logger.warn("Connected handler threw an error.", { error: String(error) });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
288
386
|
resolveConnect();
|
|
289
387
|
break;
|
|
290
388
|
case "auth.error": {
|
|
@@ -294,7 +392,7 @@ function createConsumerShardwire(options) {
|
|
|
294
392
|
message: payload.message
|
|
295
393
|
});
|
|
296
394
|
rejectConnect(payload.message);
|
|
297
|
-
rejectAllPending("Shardwire authentication failed.");
|
|
395
|
+
rejectAllPending("UNAUTHORIZED", "Shardwire authentication failed.");
|
|
298
396
|
socket?.close();
|
|
299
397
|
break;
|
|
300
398
|
}
|
|
@@ -333,8 +431,22 @@ function createConsumerShardwire(options) {
|
|
|
333
431
|
}
|
|
334
432
|
});
|
|
335
433
|
socket.on("close", () => {
|
|
434
|
+
const willReconnect = !isClosed && reconnectEnabled;
|
|
336
435
|
rejectConnect("Shardwire connection closed.");
|
|
337
436
|
isAuthed = false;
|
|
437
|
+
currentConnectionId = null;
|
|
438
|
+
rejectAllPending("DISCONNECTED", "Shardwire connection closed before command completed.");
|
|
439
|
+
for (const handler of disconnectedHandlers) {
|
|
440
|
+
try {
|
|
441
|
+
handler({
|
|
442
|
+
reason: "Shardwire connection closed.",
|
|
443
|
+
at: Date.now(),
|
|
444
|
+
willReconnect
|
|
445
|
+
});
|
|
446
|
+
} catch (error) {
|
|
447
|
+
logger.warn("Disconnected handler threw an error.", { error: String(error) });
|
|
448
|
+
}
|
|
449
|
+
}
|
|
338
450
|
if (!isClosed) {
|
|
339
451
|
scheduleReconnect();
|
|
340
452
|
}
|
|
@@ -373,7 +485,7 @@ function createConsumerShardwire(options) {
|
|
|
373
485
|
requestId: sendOptions?.requestId ?? "unknown",
|
|
374
486
|
ts: Date.now(),
|
|
375
487
|
error: {
|
|
376
|
-
code: "
|
|
488
|
+
code: "DISCONNECTED",
|
|
377
489
|
message: "Not connected to Shardwire host."
|
|
378
490
|
}
|
|
379
491
|
};
|
|
@@ -383,9 +495,13 @@ function createConsumerShardwire(options) {
|
|
|
383
495
|
const promise = new Promise((resolve, reject) => {
|
|
384
496
|
const timer = setTimeout(() => {
|
|
385
497
|
pendingRequests.delete(requestId);
|
|
386
|
-
reject(new
|
|
498
|
+
reject(new CommandRequestError("TIMEOUT", `Command "${name}" timed out after ${timeoutMs}ms.`));
|
|
387
499
|
}, timeoutMs);
|
|
388
|
-
pendingRequests.set(requestId, {
|
|
500
|
+
pendingRequests.set(requestId, {
|
|
501
|
+
resolve,
|
|
502
|
+
reject: (error) => reject(error),
|
|
503
|
+
timer
|
|
504
|
+
});
|
|
389
505
|
});
|
|
390
506
|
sendRaw(
|
|
391
507
|
stringifyEnvelope(
|
|
@@ -402,13 +518,14 @@ function createConsumerShardwire(options) {
|
|
|
402
518
|
try {
|
|
403
519
|
return await promise;
|
|
404
520
|
} catch (error) {
|
|
521
|
+
const failureCode = error instanceof CommandRequestError ? error.code : !socket || socket.readyState !== 1 ? "DISCONNECTED" : "TIMEOUT";
|
|
405
522
|
return {
|
|
406
523
|
ok: false,
|
|
407
524
|
requestId,
|
|
408
525
|
ts: Date.now(),
|
|
409
526
|
error: {
|
|
410
|
-
code:
|
|
411
|
-
message: error instanceof Error ? error.message : "Command request
|
|
527
|
+
code: failureCode,
|
|
528
|
+
message: error instanceof Error ? error.message : "Command request failed."
|
|
412
529
|
}
|
|
413
530
|
};
|
|
414
531
|
}
|
|
@@ -444,18 +561,43 @@ function createConsumerShardwire(options) {
|
|
|
444
561
|
eventHandlers.delete(name);
|
|
445
562
|
}
|
|
446
563
|
},
|
|
564
|
+
onConnected(handler) {
|
|
565
|
+
connectedHandlers.add(handler);
|
|
566
|
+
return () => {
|
|
567
|
+
connectedHandlers.delete(handler);
|
|
568
|
+
};
|
|
569
|
+
},
|
|
570
|
+
onDisconnected(handler) {
|
|
571
|
+
disconnectedHandlers.add(handler);
|
|
572
|
+
return () => {
|
|
573
|
+
disconnectedHandlers.delete(handler);
|
|
574
|
+
};
|
|
575
|
+
},
|
|
576
|
+
onReconnecting(handler) {
|
|
577
|
+
reconnectingHandlers.add(handler);
|
|
578
|
+
return () => {
|
|
579
|
+
reconnectingHandlers.delete(handler);
|
|
580
|
+
};
|
|
581
|
+
},
|
|
582
|
+
ready() {
|
|
583
|
+
return connect();
|
|
584
|
+
},
|
|
447
585
|
connected() {
|
|
448
586
|
return Boolean(socket && socket.readyState === 1 && isAuthed);
|
|
449
587
|
},
|
|
588
|
+
connectionId() {
|
|
589
|
+
return currentConnectionId;
|
|
590
|
+
},
|
|
450
591
|
async close() {
|
|
451
592
|
isClosed = true;
|
|
452
593
|
isAuthed = false;
|
|
594
|
+
currentConnectionId = null;
|
|
453
595
|
rejectConnect("Shardwire consumer has been closed.");
|
|
454
596
|
if (reconnectTimer) {
|
|
455
597
|
clearTimeout(reconnectTimer);
|
|
456
598
|
reconnectTimer = null;
|
|
457
599
|
}
|
|
458
|
-
rejectAllPending("Shardwire consumer has been closed.");
|
|
600
|
+
rejectAllPending("DISCONNECTED", "Shardwire consumer has been closed.");
|
|
459
601
|
if (!socket) {
|
|
460
602
|
return;
|
|
461
603
|
}
|
|
@@ -500,7 +642,7 @@ async function withTimeout(promise, timeoutMs, timeoutMessage = "Operation timed
|
|
|
500
642
|
resolve(value);
|
|
501
643
|
}).catch((error) => {
|
|
502
644
|
clearTimeout(timeout);
|
|
503
|
-
reject(error);
|
|
645
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
504
646
|
});
|
|
505
647
|
});
|
|
506
648
|
}
|
|
@@ -626,14 +768,25 @@ var HostWebSocketServer = class {
|
|
|
626
768
|
socket.close(CLOSE_AUTH_REQUIRED, "Authentication required.");
|
|
627
769
|
}
|
|
628
770
|
}, this.authTimeoutMs);
|
|
629
|
-
socket.on("message",
|
|
771
|
+
socket.on("message", (raw) => {
|
|
772
|
+
const serialized = typeof raw === "string" ? raw : Buffer.isBuffer(raw) ? raw.toString("utf8") : void 0;
|
|
773
|
+
if (!serialized) {
|
|
774
|
+
this.logger.warn("Invalid message payload from client.", { error: "Unsupported payload type." });
|
|
775
|
+
socket.close(CLOSE_INVALID_PAYLOAD, "Invalid payload.");
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
let parsed;
|
|
630
779
|
try {
|
|
631
|
-
|
|
632
|
-
await this.handleMessage(state, parsed);
|
|
780
|
+
parsed = parseEnvelope(serialized);
|
|
633
781
|
} catch (error) {
|
|
634
782
|
this.logger.warn("Invalid message payload from client.", { error: String(error) });
|
|
635
783
|
socket.close(CLOSE_INVALID_PAYLOAD, "Invalid payload.");
|
|
784
|
+
return;
|
|
636
785
|
}
|
|
786
|
+
void this.handleMessage(state, parsed).catch((error) => {
|
|
787
|
+
this.logger.warn("Invalid message payload from client.", { error: String(error) });
|
|
788
|
+
socket.close(CLOSE_INVALID_PAYLOAD, "Invalid payload.");
|
|
789
|
+
});
|
|
637
790
|
});
|
|
638
791
|
socket.on("close", () => {
|
|
639
792
|
clearTimeout(authTimer);
|
|
@@ -767,7 +920,7 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
767
920
|
const hostServer = new HostWebSocketServer({
|
|
768
921
|
options,
|
|
769
922
|
onCommandRequest: async (connection, payload, requestId, source) => {
|
|
770
|
-
const cacheKey = `${requestId}:${payload.name}`;
|
|
923
|
+
const cacheKey = `${connection.id}:${requestId}:${payload.name}`;
|
|
771
924
|
const cached = dedupeCache.get(cacheKey);
|
|
772
925
|
if (cached) {
|
|
773
926
|
return cached;
|
|
@@ -795,21 +948,44 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
795
948
|
context.source = source;
|
|
796
949
|
}
|
|
797
950
|
try {
|
|
798
|
-
const
|
|
951
|
+
const commandValidation = options.validation?.commands?.[payload.name];
|
|
952
|
+
const validatedRequest = parsePayloadWithSchema(commandValidation?.request, payload.data, {
|
|
953
|
+
name: payload.name,
|
|
954
|
+
stage: "command.request"
|
|
955
|
+
});
|
|
956
|
+
const maybePromise = Promise.resolve(handler(validatedRequest, context));
|
|
799
957
|
const value = await withTimeout(
|
|
800
958
|
maybePromise,
|
|
801
959
|
commandTimeoutMs,
|
|
802
960
|
`Command "${payload.name}" timed out after ${commandTimeoutMs}ms.`
|
|
803
961
|
);
|
|
962
|
+
const validatedResponse = parsePayloadWithSchema(commandValidation?.response, value, {
|
|
963
|
+
name: payload.name,
|
|
964
|
+
stage: "command.response"
|
|
965
|
+
});
|
|
804
966
|
const success = {
|
|
805
967
|
ok: true,
|
|
806
968
|
requestId,
|
|
807
969
|
ts: Date.now(),
|
|
808
|
-
data:
|
|
970
|
+
data: validatedResponse
|
|
809
971
|
};
|
|
810
972
|
dedupeCache.set(cacheKey, success);
|
|
811
973
|
return success;
|
|
812
974
|
} catch (error) {
|
|
975
|
+
if (error instanceof PayloadValidationError) {
|
|
976
|
+
const failure2 = {
|
|
977
|
+
ok: false,
|
|
978
|
+
requestId,
|
|
979
|
+
ts: Date.now(),
|
|
980
|
+
error: {
|
|
981
|
+
code: "VALIDATION_ERROR",
|
|
982
|
+
message: error.message,
|
|
983
|
+
details: error.details
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
dedupeCache.set(cacheKey, failure2);
|
|
987
|
+
return failure2;
|
|
988
|
+
}
|
|
813
989
|
const isTimeout = error instanceof Error && /timed out/i.test(error.message);
|
|
814
990
|
const failure = {
|
|
815
991
|
ok: false,
|
|
@@ -836,13 +1012,21 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
836
1012
|
},
|
|
837
1013
|
emitEvent(name, payload) {
|
|
838
1014
|
assertMessageName("event", name);
|
|
839
|
-
|
|
840
|
-
|
|
1015
|
+
const validatedPayload = parsePayloadWithSchema(options.validation?.events?.[name], payload, {
|
|
1016
|
+
name,
|
|
1017
|
+
stage: "event.emit"
|
|
1018
|
+
});
|
|
1019
|
+
assertJsonPayload("event", name, validatedPayload);
|
|
1020
|
+
hostServer.emitEvent(name, validatedPayload, options.name);
|
|
841
1021
|
},
|
|
842
1022
|
broadcast(name, payload) {
|
|
843
1023
|
assertMessageName("event", name);
|
|
844
|
-
|
|
845
|
-
|
|
1024
|
+
const validatedPayload = parsePayloadWithSchema(options.validation?.events?.[name], payload, {
|
|
1025
|
+
name,
|
|
1026
|
+
stage: "event.emit"
|
|
1027
|
+
});
|
|
1028
|
+
assertJsonPayload("event", name, validatedPayload);
|
|
1029
|
+
hostServer.emitEvent(name, validatedPayload, options.name);
|
|
846
1030
|
},
|
|
847
1031
|
close() {
|
|
848
1032
|
return hostServer.close().then(async () => {
|
|
@@ -852,6 +1036,52 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
852
1036
|
};
|
|
853
1037
|
}
|
|
854
1038
|
|
|
1039
|
+
// src/schema/index.ts
|
|
1040
|
+
function fromSafeParseSchema(schema) {
|
|
1041
|
+
return {
|
|
1042
|
+
parse(value) {
|
|
1043
|
+
const result = schema.safeParse(value);
|
|
1044
|
+
if (result.success) {
|
|
1045
|
+
return result.data;
|
|
1046
|
+
}
|
|
1047
|
+
const error = new Error(result.error.message);
|
|
1048
|
+
if (result.error.issues) {
|
|
1049
|
+
error.issues = result.error.issues;
|
|
1050
|
+
}
|
|
1051
|
+
throw error;
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// src/schema/zod.ts
|
|
1057
|
+
function normalizeZodPath(path) {
|
|
1058
|
+
if (path.length === 0) {
|
|
1059
|
+
return "";
|
|
1060
|
+
}
|
|
1061
|
+
return path.filter((segment) => typeof segment === "string" || typeof segment === "number").map((segment) => String(segment)).join(".");
|
|
1062
|
+
}
|
|
1063
|
+
function fromZodSchema(schema) {
|
|
1064
|
+
return fromSafeParseSchema({
|
|
1065
|
+
safeParse(value) {
|
|
1066
|
+
const result = schema.safeParse(value);
|
|
1067
|
+
if (result.success) {
|
|
1068
|
+
return { success: true, data: result.data };
|
|
1069
|
+
}
|
|
1070
|
+
const issues = result.error.issues.map((issue) => ({
|
|
1071
|
+
path: normalizeZodPath(issue.path),
|
|
1072
|
+
message: issue.message
|
|
1073
|
+
}));
|
|
1074
|
+
return {
|
|
1075
|
+
success: false,
|
|
1076
|
+
error: {
|
|
1077
|
+
message: "Schema validation failed.",
|
|
1078
|
+
issues
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
|
|
855
1085
|
// src/index.ts
|
|
856
1086
|
function isHostOptions(options) {
|
|
857
1087
|
return "server" in options;
|
|
@@ -887,6 +1117,8 @@ function createShardwire(options) {
|
|
|
887
1117
|
}
|
|
888
1118
|
// Annotate the CommonJS export names for ESM import in node:
|
|
889
1119
|
0 && (module.exports = {
|
|
890
|
-
createShardwire
|
|
1120
|
+
createShardwire,
|
|
1121
|
+
fromSafeParseSchema,
|
|
1122
|
+
fromZodSchema
|
|
891
1123
|
});
|
|
892
1124
|
//# sourceMappingURL=index.js.map
|