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.mjs
CHANGED
|
@@ -64,6 +64,14 @@ function stringifyEnvelope(envelope) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// src/runtime/validation.ts
|
|
67
|
+
var PayloadValidationError = class extends Error {
|
|
68
|
+
constructor(message, details) {
|
|
69
|
+
super(message);
|
|
70
|
+
this.details = details;
|
|
71
|
+
this.name = "PayloadValidationError";
|
|
72
|
+
}
|
|
73
|
+
details;
|
|
74
|
+
};
|
|
67
75
|
function isNonEmptyString(value) {
|
|
68
76
|
return typeof value === "string" && value.trim().length > 0;
|
|
69
77
|
}
|
|
@@ -102,12 +110,30 @@ function assertConsumerOptions(options) {
|
|
|
102
110
|
if (!isNonEmptyString(options.url)) {
|
|
103
111
|
throw new Error("Consumer mode requires `url`.");
|
|
104
112
|
}
|
|
113
|
+
let parsedUrl;
|
|
114
|
+
try {
|
|
115
|
+
parsedUrl = new URL(options.url);
|
|
116
|
+
} catch {
|
|
117
|
+
throw new Error("Consumer option `url` must be a valid URL.");
|
|
118
|
+
}
|
|
119
|
+
if (parsedUrl.protocol !== "ws:" && parsedUrl.protocol !== "wss:") {
|
|
120
|
+
throw new Error("Consumer option `url` must use `ws://` or `wss://`.");
|
|
121
|
+
}
|
|
122
|
+
const isLoopbackHost = parsedUrl.hostname === "localhost" || parsedUrl.hostname === "127.0.0.1" || parsedUrl.hostname === "::1";
|
|
123
|
+
if (parsedUrl.protocol === "ws:" && !isLoopbackHost && !options.allowInsecureWs) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
"Insecure `ws://` is only allowed for loopback hosts by default. Use `wss://` or set `allowInsecureWs` to true."
|
|
126
|
+
);
|
|
127
|
+
}
|
|
105
128
|
if (!isNonEmptyString(options.secret)) {
|
|
106
129
|
throw new Error("Consumer mode requires `secret`.");
|
|
107
130
|
}
|
|
108
131
|
if (options.secretId !== void 0 && !isNonEmptyString(options.secretId)) {
|
|
109
132
|
throw new Error("Consumer option `secretId` must be a non-empty string.");
|
|
110
133
|
}
|
|
134
|
+
if (options.clientName !== void 0 && !isNonEmptyString(options.clientName)) {
|
|
135
|
+
throw new Error("Consumer option `clientName` must be a non-empty string.");
|
|
136
|
+
}
|
|
111
137
|
if (options.requestTimeoutMs !== void 0) {
|
|
112
138
|
assertPositiveNumber("requestTimeoutMs", options.requestTimeoutMs);
|
|
113
139
|
}
|
|
@@ -130,9 +156,54 @@ function assertJsonPayload(kind, name, payload) {
|
|
|
130
156
|
throw new Error(`${kind} "${name}" payload must be JSON-serializable.`);
|
|
131
157
|
}
|
|
132
158
|
}
|
|
159
|
+
function normalizeSchemaIssues(error) {
|
|
160
|
+
if (!error || typeof error !== "object") {
|
|
161
|
+
return void 0;
|
|
162
|
+
}
|
|
163
|
+
const issues = error.issues;
|
|
164
|
+
if (!Array.isArray(issues)) {
|
|
165
|
+
return void 0;
|
|
166
|
+
}
|
|
167
|
+
const normalized = issues.map((issue) => {
|
|
168
|
+
if (!issue || typeof issue !== "object") {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
const message = issue.message;
|
|
172
|
+
const rawPath = issue.path;
|
|
173
|
+
if (typeof message !== "string") {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
const path = Array.isArray(rawPath) && rawPath.length > 0 ? rawPath.map((segment) => typeof segment === "string" || typeof segment === "number" ? String(segment) : "").filter(Boolean).join(".") : "";
|
|
177
|
+
return { path, message };
|
|
178
|
+
}).filter((issue) => Boolean(issue));
|
|
179
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
180
|
+
}
|
|
181
|
+
function parsePayloadWithSchema(schema, payload, context) {
|
|
182
|
+
if (!schema) {
|
|
183
|
+
return payload;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
return schema.parse(payload);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
const message = error instanceof Error && error.message.trim().length > 0 ? error.message : `Payload validation failed for ${context.stage} "${context.name}".`;
|
|
189
|
+
const issues = normalizeSchemaIssues(error);
|
|
190
|
+
throw new PayloadValidationError(message, {
|
|
191
|
+
...context,
|
|
192
|
+
...issues ? { issues } : {}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
133
196
|
|
|
134
197
|
// src/consumer/index.ts
|
|
135
198
|
var DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
|
|
199
|
+
var CommandRequestError = class extends Error {
|
|
200
|
+
constructor(code, message) {
|
|
201
|
+
super(message);
|
|
202
|
+
this.code = code;
|
|
203
|
+
this.name = "CommandRequestError";
|
|
204
|
+
}
|
|
205
|
+
code;
|
|
206
|
+
};
|
|
136
207
|
function createConsumerShardwire(options) {
|
|
137
208
|
const logger = withLogger(options.logger);
|
|
138
209
|
const reconnectEnabled = options.reconnect?.enabled ?? true;
|
|
@@ -149,8 +220,12 @@ function createConsumerShardwire(options) {
|
|
|
149
220
|
let connectResolve = null;
|
|
150
221
|
let connectReject = null;
|
|
151
222
|
let authTimeoutTimer = null;
|
|
223
|
+
let currentConnectionId = null;
|
|
152
224
|
const pendingRequests = /* @__PURE__ */ new Map();
|
|
153
225
|
const eventHandlers = /* @__PURE__ */ new Map();
|
|
226
|
+
const connectedHandlers = /* @__PURE__ */ new Set();
|
|
227
|
+
const disconnectedHandlers = /* @__PURE__ */ new Set();
|
|
228
|
+
const reconnectingHandlers = /* @__PURE__ */ new Set();
|
|
154
229
|
function clearAuthTimeout() {
|
|
155
230
|
if (authTimeoutTimer) {
|
|
156
231
|
clearTimeout(authTimeoutTimer);
|
|
@@ -179,10 +254,10 @@ function createConsumerShardwire(options) {
|
|
|
179
254
|
}
|
|
180
255
|
socket.send(data);
|
|
181
256
|
}
|
|
182
|
-
function rejectAllPending(reason) {
|
|
257
|
+
function rejectAllPending(code, reason) {
|
|
183
258
|
for (const [requestId, pending] of pendingRequests.entries()) {
|
|
184
259
|
clearTimeout(pending.timer);
|
|
185
|
-
pending.reject(new
|
|
260
|
+
pending.reject(new CommandRequestError(code, reason));
|
|
186
261
|
pendingRequests.delete(requestId);
|
|
187
262
|
}
|
|
188
263
|
}
|
|
@@ -192,6 +267,13 @@ function createConsumerShardwire(options) {
|
|
|
192
267
|
}
|
|
193
268
|
const delay = getBackoffDelay(reconnectAttempts, { initialDelayMs, maxDelayMs, jitter });
|
|
194
269
|
reconnectAttempts += 1;
|
|
270
|
+
for (const handler of reconnectingHandlers) {
|
|
271
|
+
try {
|
|
272
|
+
handler({ attempt: reconnectAttempts, delayMs: delay, at: Date.now() });
|
|
273
|
+
} catch (error) {
|
|
274
|
+
logger.warn("Reconnect handler threw an error.", { error: String(error) });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
195
277
|
reconnectTimer = setTimeout(() => {
|
|
196
278
|
reconnectTimer = null;
|
|
197
279
|
void connect().catch((error) => {
|
|
@@ -230,9 +312,11 @@ function createConsumerShardwire(options) {
|
|
|
230
312
|
socket.on("open", () => {
|
|
231
313
|
reconnectAttempts = 0;
|
|
232
314
|
isAuthed = false;
|
|
315
|
+
currentConnectionId = null;
|
|
233
316
|
const hello = makeEnvelope("auth.hello", {
|
|
234
317
|
secret: options.secret,
|
|
235
|
-
secretId: options.secretId
|
|
318
|
+
secretId: options.secretId,
|
|
319
|
+
clientName: options.clientName
|
|
236
320
|
});
|
|
237
321
|
socket?.send(stringifyEnvelope(hello));
|
|
238
322
|
authTimeoutTimer = setTimeout(() => {
|
|
@@ -249,6 +333,18 @@ function createConsumerShardwire(options) {
|
|
|
249
333
|
switch (envelope.type) {
|
|
250
334
|
case "auth.ok":
|
|
251
335
|
isAuthed = true;
|
|
336
|
+
if (envelope.payload && typeof envelope.payload === "object" && "connectionId" in envelope.payload && typeof envelope.payload.connectionId === "string") {
|
|
337
|
+
currentConnectionId = envelope.payload.connectionId;
|
|
338
|
+
}
|
|
339
|
+
if (currentConnectionId) {
|
|
340
|
+
for (const handler of connectedHandlers) {
|
|
341
|
+
try {
|
|
342
|
+
handler({ connectionId: currentConnectionId, connectedAt: Date.now() });
|
|
343
|
+
} catch (error) {
|
|
344
|
+
logger.warn("Connected handler threw an error.", { error: String(error) });
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
252
348
|
resolveConnect();
|
|
253
349
|
break;
|
|
254
350
|
case "auth.error": {
|
|
@@ -258,7 +354,7 @@ function createConsumerShardwire(options) {
|
|
|
258
354
|
message: payload.message
|
|
259
355
|
});
|
|
260
356
|
rejectConnect(payload.message);
|
|
261
|
-
rejectAllPending("Shardwire authentication failed.");
|
|
357
|
+
rejectAllPending("UNAUTHORIZED", "Shardwire authentication failed.");
|
|
262
358
|
socket?.close();
|
|
263
359
|
break;
|
|
264
360
|
}
|
|
@@ -297,8 +393,22 @@ function createConsumerShardwire(options) {
|
|
|
297
393
|
}
|
|
298
394
|
});
|
|
299
395
|
socket.on("close", () => {
|
|
396
|
+
const willReconnect = !isClosed && reconnectEnabled;
|
|
300
397
|
rejectConnect("Shardwire connection closed.");
|
|
301
398
|
isAuthed = false;
|
|
399
|
+
currentConnectionId = null;
|
|
400
|
+
rejectAllPending("DISCONNECTED", "Shardwire connection closed before command completed.");
|
|
401
|
+
for (const handler of disconnectedHandlers) {
|
|
402
|
+
try {
|
|
403
|
+
handler({
|
|
404
|
+
reason: "Shardwire connection closed.",
|
|
405
|
+
at: Date.now(),
|
|
406
|
+
willReconnect
|
|
407
|
+
});
|
|
408
|
+
} catch (error) {
|
|
409
|
+
logger.warn("Disconnected handler threw an error.", { error: String(error) });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
302
412
|
if (!isClosed) {
|
|
303
413
|
scheduleReconnect();
|
|
304
414
|
}
|
|
@@ -337,7 +447,7 @@ function createConsumerShardwire(options) {
|
|
|
337
447
|
requestId: sendOptions?.requestId ?? "unknown",
|
|
338
448
|
ts: Date.now(),
|
|
339
449
|
error: {
|
|
340
|
-
code: "
|
|
450
|
+
code: "DISCONNECTED",
|
|
341
451
|
message: "Not connected to Shardwire host."
|
|
342
452
|
}
|
|
343
453
|
};
|
|
@@ -347,9 +457,13 @@ function createConsumerShardwire(options) {
|
|
|
347
457
|
const promise = new Promise((resolve, reject) => {
|
|
348
458
|
const timer = setTimeout(() => {
|
|
349
459
|
pendingRequests.delete(requestId);
|
|
350
|
-
reject(new
|
|
460
|
+
reject(new CommandRequestError("TIMEOUT", `Command "${name}" timed out after ${timeoutMs}ms.`));
|
|
351
461
|
}, timeoutMs);
|
|
352
|
-
pendingRequests.set(requestId, {
|
|
462
|
+
pendingRequests.set(requestId, {
|
|
463
|
+
resolve,
|
|
464
|
+
reject: (error) => reject(error),
|
|
465
|
+
timer
|
|
466
|
+
});
|
|
353
467
|
});
|
|
354
468
|
sendRaw(
|
|
355
469
|
stringifyEnvelope(
|
|
@@ -366,13 +480,14 @@ function createConsumerShardwire(options) {
|
|
|
366
480
|
try {
|
|
367
481
|
return await promise;
|
|
368
482
|
} catch (error) {
|
|
483
|
+
const failureCode = error instanceof CommandRequestError ? error.code : !socket || socket.readyState !== 1 ? "DISCONNECTED" : "TIMEOUT";
|
|
369
484
|
return {
|
|
370
485
|
ok: false,
|
|
371
486
|
requestId,
|
|
372
487
|
ts: Date.now(),
|
|
373
488
|
error: {
|
|
374
|
-
code:
|
|
375
|
-
message: error instanceof Error ? error.message : "Command request
|
|
489
|
+
code: failureCode,
|
|
490
|
+
message: error instanceof Error ? error.message : "Command request failed."
|
|
376
491
|
}
|
|
377
492
|
};
|
|
378
493
|
}
|
|
@@ -408,18 +523,43 @@ function createConsumerShardwire(options) {
|
|
|
408
523
|
eventHandlers.delete(name);
|
|
409
524
|
}
|
|
410
525
|
},
|
|
526
|
+
onConnected(handler) {
|
|
527
|
+
connectedHandlers.add(handler);
|
|
528
|
+
return () => {
|
|
529
|
+
connectedHandlers.delete(handler);
|
|
530
|
+
};
|
|
531
|
+
},
|
|
532
|
+
onDisconnected(handler) {
|
|
533
|
+
disconnectedHandlers.add(handler);
|
|
534
|
+
return () => {
|
|
535
|
+
disconnectedHandlers.delete(handler);
|
|
536
|
+
};
|
|
537
|
+
},
|
|
538
|
+
onReconnecting(handler) {
|
|
539
|
+
reconnectingHandlers.add(handler);
|
|
540
|
+
return () => {
|
|
541
|
+
reconnectingHandlers.delete(handler);
|
|
542
|
+
};
|
|
543
|
+
},
|
|
544
|
+
ready() {
|
|
545
|
+
return connect();
|
|
546
|
+
},
|
|
411
547
|
connected() {
|
|
412
548
|
return Boolean(socket && socket.readyState === 1 && isAuthed);
|
|
413
549
|
},
|
|
550
|
+
connectionId() {
|
|
551
|
+
return currentConnectionId;
|
|
552
|
+
},
|
|
414
553
|
async close() {
|
|
415
554
|
isClosed = true;
|
|
416
555
|
isAuthed = false;
|
|
556
|
+
currentConnectionId = null;
|
|
417
557
|
rejectConnect("Shardwire consumer has been closed.");
|
|
418
558
|
if (reconnectTimer) {
|
|
419
559
|
clearTimeout(reconnectTimer);
|
|
420
560
|
reconnectTimer = null;
|
|
421
561
|
}
|
|
422
|
-
rejectAllPending("Shardwire consumer has been closed.");
|
|
562
|
+
rejectAllPending("DISCONNECTED", "Shardwire consumer has been closed.");
|
|
423
563
|
if (!socket) {
|
|
424
564
|
return;
|
|
425
565
|
}
|
|
@@ -464,7 +604,7 @@ async function withTimeout(promise, timeoutMs, timeoutMessage = "Operation timed
|
|
|
464
604
|
resolve(value);
|
|
465
605
|
}).catch((error) => {
|
|
466
606
|
clearTimeout(timeout);
|
|
467
|
-
reject(error);
|
|
607
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
468
608
|
});
|
|
469
609
|
});
|
|
470
610
|
}
|
|
@@ -590,14 +730,25 @@ var HostWebSocketServer = class {
|
|
|
590
730
|
socket.close(CLOSE_AUTH_REQUIRED, "Authentication required.");
|
|
591
731
|
}
|
|
592
732
|
}, this.authTimeoutMs);
|
|
593
|
-
socket.on("message",
|
|
733
|
+
socket.on("message", (raw) => {
|
|
734
|
+
const serialized = typeof raw === "string" ? raw : Buffer.isBuffer(raw) ? raw.toString("utf8") : void 0;
|
|
735
|
+
if (!serialized) {
|
|
736
|
+
this.logger.warn("Invalid message payload from client.", { error: "Unsupported payload type." });
|
|
737
|
+
socket.close(CLOSE_INVALID_PAYLOAD, "Invalid payload.");
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
let parsed;
|
|
594
741
|
try {
|
|
595
|
-
|
|
596
|
-
await this.handleMessage(state, parsed);
|
|
742
|
+
parsed = parseEnvelope(serialized);
|
|
597
743
|
} catch (error) {
|
|
598
744
|
this.logger.warn("Invalid message payload from client.", { error: String(error) });
|
|
599
745
|
socket.close(CLOSE_INVALID_PAYLOAD, "Invalid payload.");
|
|
746
|
+
return;
|
|
600
747
|
}
|
|
748
|
+
void this.handleMessage(state, parsed).catch((error) => {
|
|
749
|
+
this.logger.warn("Invalid message payload from client.", { error: String(error) });
|
|
750
|
+
socket.close(CLOSE_INVALID_PAYLOAD, "Invalid payload.");
|
|
751
|
+
});
|
|
601
752
|
});
|
|
602
753
|
socket.on("close", () => {
|
|
603
754
|
clearTimeout(authTimer);
|
|
@@ -731,7 +882,7 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
731
882
|
const hostServer = new HostWebSocketServer({
|
|
732
883
|
options,
|
|
733
884
|
onCommandRequest: async (connection, payload, requestId, source) => {
|
|
734
|
-
const cacheKey = `${requestId}:${payload.name}`;
|
|
885
|
+
const cacheKey = `${connection.id}:${requestId}:${payload.name}`;
|
|
735
886
|
const cached = dedupeCache.get(cacheKey);
|
|
736
887
|
if (cached) {
|
|
737
888
|
return cached;
|
|
@@ -759,21 +910,44 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
759
910
|
context.source = source;
|
|
760
911
|
}
|
|
761
912
|
try {
|
|
762
|
-
const
|
|
913
|
+
const commandValidation = options.validation?.commands?.[payload.name];
|
|
914
|
+
const validatedRequest = parsePayloadWithSchema(commandValidation?.request, payload.data, {
|
|
915
|
+
name: payload.name,
|
|
916
|
+
stage: "command.request"
|
|
917
|
+
});
|
|
918
|
+
const maybePromise = Promise.resolve(handler(validatedRequest, context));
|
|
763
919
|
const value = await withTimeout(
|
|
764
920
|
maybePromise,
|
|
765
921
|
commandTimeoutMs,
|
|
766
922
|
`Command "${payload.name}" timed out after ${commandTimeoutMs}ms.`
|
|
767
923
|
);
|
|
924
|
+
const validatedResponse = parsePayloadWithSchema(commandValidation?.response, value, {
|
|
925
|
+
name: payload.name,
|
|
926
|
+
stage: "command.response"
|
|
927
|
+
});
|
|
768
928
|
const success = {
|
|
769
929
|
ok: true,
|
|
770
930
|
requestId,
|
|
771
931
|
ts: Date.now(),
|
|
772
|
-
data:
|
|
932
|
+
data: validatedResponse
|
|
773
933
|
};
|
|
774
934
|
dedupeCache.set(cacheKey, success);
|
|
775
935
|
return success;
|
|
776
936
|
} catch (error) {
|
|
937
|
+
if (error instanceof PayloadValidationError) {
|
|
938
|
+
const failure2 = {
|
|
939
|
+
ok: false,
|
|
940
|
+
requestId,
|
|
941
|
+
ts: Date.now(),
|
|
942
|
+
error: {
|
|
943
|
+
code: "VALIDATION_ERROR",
|
|
944
|
+
message: error.message,
|
|
945
|
+
details: error.details
|
|
946
|
+
}
|
|
947
|
+
};
|
|
948
|
+
dedupeCache.set(cacheKey, failure2);
|
|
949
|
+
return failure2;
|
|
950
|
+
}
|
|
777
951
|
const isTimeout = error instanceof Error && /timed out/i.test(error.message);
|
|
778
952
|
const failure = {
|
|
779
953
|
ok: false,
|
|
@@ -800,13 +974,21 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
800
974
|
},
|
|
801
975
|
emitEvent(name, payload) {
|
|
802
976
|
assertMessageName("event", name);
|
|
803
|
-
|
|
804
|
-
|
|
977
|
+
const validatedPayload = parsePayloadWithSchema(options.validation?.events?.[name], payload, {
|
|
978
|
+
name,
|
|
979
|
+
stage: "event.emit"
|
|
980
|
+
});
|
|
981
|
+
assertJsonPayload("event", name, validatedPayload);
|
|
982
|
+
hostServer.emitEvent(name, validatedPayload, options.name);
|
|
805
983
|
},
|
|
806
984
|
broadcast(name, payload) {
|
|
807
985
|
assertMessageName("event", name);
|
|
808
|
-
|
|
809
|
-
|
|
986
|
+
const validatedPayload = parsePayloadWithSchema(options.validation?.events?.[name], payload, {
|
|
987
|
+
name,
|
|
988
|
+
stage: "event.emit"
|
|
989
|
+
});
|
|
990
|
+
assertJsonPayload("event", name, validatedPayload);
|
|
991
|
+
hostServer.emitEvent(name, validatedPayload, options.name);
|
|
810
992
|
},
|
|
811
993
|
close() {
|
|
812
994
|
return hostServer.close().then(async () => {
|
|
@@ -816,6 +998,52 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
816
998
|
};
|
|
817
999
|
}
|
|
818
1000
|
|
|
1001
|
+
// src/schema/index.ts
|
|
1002
|
+
function fromSafeParseSchema(schema) {
|
|
1003
|
+
return {
|
|
1004
|
+
parse(value) {
|
|
1005
|
+
const result = schema.safeParse(value);
|
|
1006
|
+
if (result.success) {
|
|
1007
|
+
return result.data;
|
|
1008
|
+
}
|
|
1009
|
+
const error = new Error(result.error.message);
|
|
1010
|
+
if (result.error.issues) {
|
|
1011
|
+
error.issues = result.error.issues;
|
|
1012
|
+
}
|
|
1013
|
+
throw error;
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// src/schema/zod.ts
|
|
1019
|
+
function normalizeZodPath(path) {
|
|
1020
|
+
if (path.length === 0) {
|
|
1021
|
+
return "";
|
|
1022
|
+
}
|
|
1023
|
+
return path.filter((segment) => typeof segment === "string" || typeof segment === "number").map((segment) => String(segment)).join(".");
|
|
1024
|
+
}
|
|
1025
|
+
function fromZodSchema(schema) {
|
|
1026
|
+
return fromSafeParseSchema({
|
|
1027
|
+
safeParse(value) {
|
|
1028
|
+
const result = schema.safeParse(value);
|
|
1029
|
+
if (result.success) {
|
|
1030
|
+
return { success: true, data: result.data };
|
|
1031
|
+
}
|
|
1032
|
+
const issues = result.error.issues.map((issue) => ({
|
|
1033
|
+
path: normalizeZodPath(issue.path),
|
|
1034
|
+
message: issue.message
|
|
1035
|
+
}));
|
|
1036
|
+
return {
|
|
1037
|
+
success: false,
|
|
1038
|
+
error: {
|
|
1039
|
+
message: "Schema validation failed.",
|
|
1040
|
+
issues
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
|
|
819
1047
|
// src/index.ts
|
|
820
1048
|
function isHostOptions(options) {
|
|
821
1049
|
return "server" in options;
|
|
@@ -850,6 +1078,8 @@ function createShardwire(options) {
|
|
|
850
1078
|
});
|
|
851
1079
|
}
|
|
852
1080
|
export {
|
|
853
|
-
createShardwire
|
|
1081
|
+
createShardwire,
|
|
1082
|
+
fromSafeParseSchema,
|
|
1083
|
+
fromZodSchema
|
|
854
1084
|
};
|
|
855
1085
|
//# sourceMappingURL=index.mjs.map
|