shardwire 0.0.1 → 0.1.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 +251 -55
- package/dist/index.d.mts +75 -7
- package/dist/index.d.ts +75 -7
- package/dist/index.js +267 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +264 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +27 -5
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
|
}
|
|
@@ -113,8 +123,16 @@ function assertHostOptions(options) {
|
|
|
113
123
|
throw new Error("Host mode requires a server configuration.");
|
|
114
124
|
}
|
|
115
125
|
assertPositiveNumber("server.port", options.server.port);
|
|
116
|
-
if (!
|
|
117
|
-
throw new Error("server.
|
|
126
|
+
if (!Array.isArray(options.server.secrets) || options.server.secrets.length === 0) {
|
|
127
|
+
throw new Error("server.secrets must contain at least one secret.");
|
|
128
|
+
}
|
|
129
|
+
for (const [index, secret] of options.server.secrets.entries()) {
|
|
130
|
+
if (!isNonEmptyString(secret)) {
|
|
131
|
+
throw new Error(`server.secrets[${index}] must be a non-empty string.`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (options.server.primarySecretId !== void 0 && !options.server.secrets.some((_, index) => options.server.primarySecretId === `s${index}`)) {
|
|
135
|
+
throw new Error("server.primarySecretId must reference an existing secret id.");
|
|
118
136
|
}
|
|
119
137
|
if (options.server.heartbeatMs !== void 0) {
|
|
120
138
|
assertPositiveNumber("server.heartbeatMs", options.server.heartbeatMs);
|
|
@@ -133,6 +151,12 @@ function assertConsumerOptions(options) {
|
|
|
133
151
|
if (!isNonEmptyString(options.secret)) {
|
|
134
152
|
throw new Error("Consumer mode requires `secret`.");
|
|
135
153
|
}
|
|
154
|
+
if (options.secretId !== void 0 && !isNonEmptyString(options.secretId)) {
|
|
155
|
+
throw new Error("Consumer option `secretId` must be a non-empty string.");
|
|
156
|
+
}
|
|
157
|
+
if (options.clientName !== void 0 && !isNonEmptyString(options.clientName)) {
|
|
158
|
+
throw new Error("Consumer option `clientName` must be a non-empty string.");
|
|
159
|
+
}
|
|
136
160
|
if (options.requestTimeoutMs !== void 0) {
|
|
137
161
|
assertPositiveNumber("requestTimeoutMs", options.requestTimeoutMs);
|
|
138
162
|
}
|
|
@@ -155,9 +179,54 @@ function assertJsonPayload(kind, name, payload) {
|
|
|
155
179
|
throw new Error(`${kind} "${name}" payload must be JSON-serializable.`);
|
|
156
180
|
}
|
|
157
181
|
}
|
|
182
|
+
function normalizeSchemaIssues(error) {
|
|
183
|
+
if (!error || typeof error !== "object") {
|
|
184
|
+
return void 0;
|
|
185
|
+
}
|
|
186
|
+
const issues = error.issues;
|
|
187
|
+
if (!Array.isArray(issues)) {
|
|
188
|
+
return void 0;
|
|
189
|
+
}
|
|
190
|
+
const normalized = issues.map((issue) => {
|
|
191
|
+
if (!issue || typeof issue !== "object") {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
const message = issue.message;
|
|
195
|
+
const rawPath = issue.path;
|
|
196
|
+
if (typeof message !== "string") {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
const path = Array.isArray(rawPath) && rawPath.length > 0 ? rawPath.map((segment) => typeof segment === "string" || typeof segment === "number" ? String(segment) : "").filter(Boolean).join(".") : "";
|
|
200
|
+
return { path, message };
|
|
201
|
+
}).filter((issue) => Boolean(issue));
|
|
202
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
203
|
+
}
|
|
204
|
+
function parsePayloadWithSchema(schema, payload, context) {
|
|
205
|
+
if (!schema) {
|
|
206
|
+
return payload;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
return schema.parse(payload);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
const message = error instanceof Error && error.message.trim().length > 0 ? error.message : `Payload validation failed for ${context.stage} "${context.name}".`;
|
|
212
|
+
const issues = normalizeSchemaIssues(error);
|
|
213
|
+
throw new PayloadValidationError(message, {
|
|
214
|
+
...context,
|
|
215
|
+
...issues ? { issues } : {}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
158
219
|
|
|
159
220
|
// src/consumer/index.ts
|
|
160
221
|
var DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
|
|
222
|
+
var CommandRequestError = class extends Error {
|
|
223
|
+
constructor(code, message) {
|
|
224
|
+
super(message);
|
|
225
|
+
this.code = code;
|
|
226
|
+
this.name = "CommandRequestError";
|
|
227
|
+
}
|
|
228
|
+
code;
|
|
229
|
+
};
|
|
161
230
|
function createConsumerShardwire(options) {
|
|
162
231
|
const logger = withLogger(options.logger);
|
|
163
232
|
const reconnectEnabled = options.reconnect?.enabled ?? true;
|
|
@@ -174,8 +243,12 @@ function createConsumerShardwire(options) {
|
|
|
174
243
|
let connectResolve = null;
|
|
175
244
|
let connectReject = null;
|
|
176
245
|
let authTimeoutTimer = null;
|
|
246
|
+
let currentConnectionId = null;
|
|
177
247
|
const pendingRequests = /* @__PURE__ */ new Map();
|
|
178
248
|
const eventHandlers = /* @__PURE__ */ new Map();
|
|
249
|
+
const connectedHandlers = /* @__PURE__ */ new Set();
|
|
250
|
+
const disconnectedHandlers = /* @__PURE__ */ new Set();
|
|
251
|
+
const reconnectingHandlers = /* @__PURE__ */ new Set();
|
|
179
252
|
function clearAuthTimeout() {
|
|
180
253
|
if (authTimeoutTimer) {
|
|
181
254
|
clearTimeout(authTimeoutTimer);
|
|
@@ -204,10 +277,10 @@ function createConsumerShardwire(options) {
|
|
|
204
277
|
}
|
|
205
278
|
socket.send(data);
|
|
206
279
|
}
|
|
207
|
-
function rejectAllPending(reason) {
|
|
280
|
+
function rejectAllPending(code, reason) {
|
|
208
281
|
for (const [requestId, pending] of pendingRequests.entries()) {
|
|
209
282
|
clearTimeout(pending.timer);
|
|
210
|
-
pending.reject(new
|
|
283
|
+
pending.reject(new CommandRequestError(code, reason));
|
|
211
284
|
pendingRequests.delete(requestId);
|
|
212
285
|
}
|
|
213
286
|
}
|
|
@@ -217,6 +290,13 @@ function createConsumerShardwire(options) {
|
|
|
217
290
|
}
|
|
218
291
|
const delay = getBackoffDelay(reconnectAttempts, { initialDelayMs, maxDelayMs, jitter });
|
|
219
292
|
reconnectAttempts += 1;
|
|
293
|
+
for (const handler of reconnectingHandlers) {
|
|
294
|
+
try {
|
|
295
|
+
handler({ attempt: reconnectAttempts, delayMs: delay, at: Date.now() });
|
|
296
|
+
} catch (error) {
|
|
297
|
+
logger.warn("Reconnect handler threw an error.", { error: String(error) });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
220
300
|
reconnectTimer = setTimeout(() => {
|
|
221
301
|
reconnectTimer = null;
|
|
222
302
|
void connect().catch((error) => {
|
|
@@ -255,7 +335,12 @@ function createConsumerShardwire(options) {
|
|
|
255
335
|
socket.on("open", () => {
|
|
256
336
|
reconnectAttempts = 0;
|
|
257
337
|
isAuthed = false;
|
|
258
|
-
|
|
338
|
+
currentConnectionId = null;
|
|
339
|
+
const hello = makeEnvelope("auth.hello", {
|
|
340
|
+
secret: options.secret,
|
|
341
|
+
secretId: options.secretId,
|
|
342
|
+
clientName: options.clientName
|
|
343
|
+
});
|
|
259
344
|
socket?.send(stringifyEnvelope(hello));
|
|
260
345
|
authTimeoutTimer = setTimeout(() => {
|
|
261
346
|
if (!isAuthed) {
|
|
@@ -271,6 +356,18 @@ function createConsumerShardwire(options) {
|
|
|
271
356
|
switch (envelope.type) {
|
|
272
357
|
case "auth.ok":
|
|
273
358
|
isAuthed = true;
|
|
359
|
+
if (envelope.payload && typeof envelope.payload === "object" && "connectionId" in envelope.payload && typeof envelope.payload.connectionId === "string") {
|
|
360
|
+
currentConnectionId = envelope.payload.connectionId;
|
|
361
|
+
}
|
|
362
|
+
if (currentConnectionId) {
|
|
363
|
+
for (const handler of connectedHandlers) {
|
|
364
|
+
try {
|
|
365
|
+
handler({ connectionId: currentConnectionId, connectedAt: Date.now() });
|
|
366
|
+
} catch (error) {
|
|
367
|
+
logger.warn("Connected handler threw an error.", { error: String(error) });
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
274
371
|
resolveConnect();
|
|
275
372
|
break;
|
|
276
373
|
case "auth.error": {
|
|
@@ -280,7 +377,7 @@ function createConsumerShardwire(options) {
|
|
|
280
377
|
message: payload.message
|
|
281
378
|
});
|
|
282
379
|
rejectConnect(payload.message);
|
|
283
|
-
rejectAllPending("Shardwire authentication failed.");
|
|
380
|
+
rejectAllPending("UNAUTHORIZED", "Shardwire authentication failed.");
|
|
284
381
|
socket?.close();
|
|
285
382
|
break;
|
|
286
383
|
}
|
|
@@ -319,8 +416,22 @@ function createConsumerShardwire(options) {
|
|
|
319
416
|
}
|
|
320
417
|
});
|
|
321
418
|
socket.on("close", () => {
|
|
419
|
+
const willReconnect = !isClosed && reconnectEnabled;
|
|
322
420
|
rejectConnect("Shardwire connection closed.");
|
|
323
421
|
isAuthed = false;
|
|
422
|
+
currentConnectionId = null;
|
|
423
|
+
rejectAllPending("DISCONNECTED", "Shardwire connection closed before command completed.");
|
|
424
|
+
for (const handler of disconnectedHandlers) {
|
|
425
|
+
try {
|
|
426
|
+
handler({
|
|
427
|
+
reason: "Shardwire connection closed.",
|
|
428
|
+
at: Date.now(),
|
|
429
|
+
willReconnect
|
|
430
|
+
});
|
|
431
|
+
} catch (error) {
|
|
432
|
+
logger.warn("Disconnected handler threw an error.", { error: String(error) });
|
|
433
|
+
}
|
|
434
|
+
}
|
|
324
435
|
if (!isClosed) {
|
|
325
436
|
scheduleReconnect();
|
|
326
437
|
}
|
|
@@ -347,7 +458,7 @@ function createConsumerShardwire(options) {
|
|
|
347
458
|
requestId: sendOptions?.requestId ?? "unknown",
|
|
348
459
|
ts: Date.now(),
|
|
349
460
|
error: {
|
|
350
|
-
code: "
|
|
461
|
+
code: "UNAUTHORIZED",
|
|
351
462
|
message: error instanceof Error ? error.message : "Failed to authenticate."
|
|
352
463
|
}
|
|
353
464
|
};
|
|
@@ -359,7 +470,7 @@ function createConsumerShardwire(options) {
|
|
|
359
470
|
requestId: sendOptions?.requestId ?? "unknown",
|
|
360
471
|
ts: Date.now(),
|
|
361
472
|
error: {
|
|
362
|
-
code: "
|
|
473
|
+
code: "DISCONNECTED",
|
|
363
474
|
message: "Not connected to Shardwire host."
|
|
364
475
|
}
|
|
365
476
|
};
|
|
@@ -369,9 +480,13 @@ function createConsumerShardwire(options) {
|
|
|
369
480
|
const promise = new Promise((resolve, reject) => {
|
|
370
481
|
const timer = setTimeout(() => {
|
|
371
482
|
pendingRequests.delete(requestId);
|
|
372
|
-
reject(new
|
|
483
|
+
reject(new CommandRequestError("TIMEOUT", `Command "${name}" timed out after ${timeoutMs}ms.`));
|
|
373
484
|
}, timeoutMs);
|
|
374
|
-
pendingRequests.set(requestId, {
|
|
485
|
+
pendingRequests.set(requestId, {
|
|
486
|
+
resolve,
|
|
487
|
+
reject: (error) => reject(error),
|
|
488
|
+
timer
|
|
489
|
+
});
|
|
375
490
|
});
|
|
376
491
|
sendRaw(
|
|
377
492
|
stringifyEnvelope(
|
|
@@ -388,13 +503,14 @@ function createConsumerShardwire(options) {
|
|
|
388
503
|
try {
|
|
389
504
|
return await promise;
|
|
390
505
|
} catch (error) {
|
|
506
|
+
const failureCode = error instanceof CommandRequestError ? error.code : !socket || socket.readyState !== 1 ? "DISCONNECTED" : "TIMEOUT";
|
|
391
507
|
return {
|
|
392
508
|
ok: false,
|
|
393
509
|
requestId,
|
|
394
510
|
ts: Date.now(),
|
|
395
511
|
error: {
|
|
396
|
-
code:
|
|
397
|
-
message: error instanceof Error ? error.message : "Command request
|
|
512
|
+
code: failureCode,
|
|
513
|
+
message: error instanceof Error ? error.message : "Command request failed."
|
|
398
514
|
}
|
|
399
515
|
};
|
|
400
516
|
}
|
|
@@ -430,18 +546,43 @@ function createConsumerShardwire(options) {
|
|
|
430
546
|
eventHandlers.delete(name);
|
|
431
547
|
}
|
|
432
548
|
},
|
|
549
|
+
onConnected(handler) {
|
|
550
|
+
connectedHandlers.add(handler);
|
|
551
|
+
return () => {
|
|
552
|
+
connectedHandlers.delete(handler);
|
|
553
|
+
};
|
|
554
|
+
},
|
|
555
|
+
onDisconnected(handler) {
|
|
556
|
+
disconnectedHandlers.add(handler);
|
|
557
|
+
return () => {
|
|
558
|
+
disconnectedHandlers.delete(handler);
|
|
559
|
+
};
|
|
560
|
+
},
|
|
561
|
+
onReconnecting(handler) {
|
|
562
|
+
reconnectingHandlers.add(handler);
|
|
563
|
+
return () => {
|
|
564
|
+
reconnectingHandlers.delete(handler);
|
|
565
|
+
};
|
|
566
|
+
},
|
|
567
|
+
ready() {
|
|
568
|
+
return connect();
|
|
569
|
+
},
|
|
433
570
|
connected() {
|
|
434
571
|
return Boolean(socket && socket.readyState === 1 && isAuthed);
|
|
435
572
|
},
|
|
573
|
+
connectionId() {
|
|
574
|
+
return currentConnectionId;
|
|
575
|
+
},
|
|
436
576
|
async close() {
|
|
437
577
|
isClosed = true;
|
|
438
578
|
isAuthed = false;
|
|
579
|
+
currentConnectionId = null;
|
|
439
580
|
rejectConnect("Shardwire consumer has been closed.");
|
|
440
581
|
if (reconnectTimer) {
|
|
441
582
|
clearTimeout(reconnectTimer);
|
|
442
583
|
reconnectTimer = null;
|
|
443
584
|
}
|
|
444
|
-
rejectAllPending("Shardwire consumer has been closed.");
|
|
585
|
+
rejectAllPending("DISCONNECTED", "Shardwire consumer has been closed.");
|
|
445
586
|
if (!socket) {
|
|
446
587
|
return;
|
|
447
588
|
}
|
|
@@ -525,6 +666,9 @@ function isSecretValid(provided, expected) {
|
|
|
525
666
|
}
|
|
526
667
|
return (0, import_node_crypto2.timingSafeEqual)(providedBuffer, expectedBuffer);
|
|
527
668
|
}
|
|
669
|
+
function getSecretId(secretIndex) {
|
|
670
|
+
return `s${secretIndex}`;
|
|
671
|
+
}
|
|
528
672
|
|
|
529
673
|
// src/transport/ws/host-server.ts
|
|
530
674
|
var CLOSE_AUTH_REQUIRED = 4001;
|
|
@@ -643,13 +787,33 @@ var HostWebSocketServer = class {
|
|
|
643
787
|
return;
|
|
644
788
|
}
|
|
645
789
|
const payload = envelope.payload;
|
|
646
|
-
|
|
790
|
+
const providedSecret = payload?.secret;
|
|
791
|
+
const knownSecrets = this.config.options.server.secrets;
|
|
792
|
+
const secretId = payload?.secretId;
|
|
793
|
+
let authReason = null;
|
|
794
|
+
if (!providedSecret) {
|
|
795
|
+
authReason = "invalid_secret";
|
|
796
|
+
} else if (secretId) {
|
|
797
|
+
const secretIndex = knownSecrets.findIndex((_, index) => getSecretId(index) === secretId);
|
|
798
|
+
if (secretIndex < 0) {
|
|
799
|
+
authReason = "unknown_secret_id";
|
|
800
|
+
} else {
|
|
801
|
+
const expectedSecret = knownSecrets[secretIndex];
|
|
802
|
+
if (!expectedSecret || !isSecretValid(providedSecret, expectedSecret)) {
|
|
803
|
+
authReason = "invalid_secret";
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
} else if (!knownSecrets.some((secret) => isSecretValid(providedSecret, secret))) {
|
|
807
|
+
authReason = "invalid_secret";
|
|
808
|
+
}
|
|
809
|
+
if (authReason) {
|
|
647
810
|
this.safeSend(
|
|
648
811
|
state.socket,
|
|
649
812
|
stringifyEnvelope(
|
|
650
813
|
makeEnvelope("auth.error", {
|
|
651
|
-
code: "
|
|
652
|
-
|
|
814
|
+
code: "UNAUTHORIZED",
|
|
815
|
+
reason: authReason,
|
|
816
|
+
message: "Authentication failed."
|
|
653
817
|
})
|
|
654
818
|
)
|
|
655
819
|
);
|
|
@@ -758,21 +922,44 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
758
922
|
context.source = source;
|
|
759
923
|
}
|
|
760
924
|
try {
|
|
761
|
-
const
|
|
925
|
+
const commandValidation = options.validation?.commands?.[payload.name];
|
|
926
|
+
const validatedRequest = parsePayloadWithSchema(commandValidation?.request, payload.data, {
|
|
927
|
+
name: payload.name,
|
|
928
|
+
stage: "command.request"
|
|
929
|
+
});
|
|
930
|
+
const maybePromise = Promise.resolve(handler(validatedRequest, context));
|
|
762
931
|
const value = await withTimeout(
|
|
763
932
|
maybePromise,
|
|
764
933
|
commandTimeoutMs,
|
|
765
934
|
`Command "${payload.name}" timed out after ${commandTimeoutMs}ms.`
|
|
766
935
|
);
|
|
936
|
+
const validatedResponse = parsePayloadWithSchema(commandValidation?.response, value, {
|
|
937
|
+
name: payload.name,
|
|
938
|
+
stage: "command.response"
|
|
939
|
+
});
|
|
767
940
|
const success = {
|
|
768
941
|
ok: true,
|
|
769
942
|
requestId,
|
|
770
943
|
ts: Date.now(),
|
|
771
|
-
data:
|
|
944
|
+
data: validatedResponse
|
|
772
945
|
};
|
|
773
946
|
dedupeCache.set(cacheKey, success);
|
|
774
947
|
return success;
|
|
775
948
|
} catch (error) {
|
|
949
|
+
if (error instanceof PayloadValidationError) {
|
|
950
|
+
const failure2 = {
|
|
951
|
+
ok: false,
|
|
952
|
+
requestId,
|
|
953
|
+
ts: Date.now(),
|
|
954
|
+
error: {
|
|
955
|
+
code: "VALIDATION_ERROR",
|
|
956
|
+
message: error.message,
|
|
957
|
+
details: error.details
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
dedupeCache.set(cacheKey, failure2);
|
|
961
|
+
return failure2;
|
|
962
|
+
}
|
|
776
963
|
const isTimeout = error instanceof Error && /timed out/i.test(error.message);
|
|
777
964
|
const failure = {
|
|
778
965
|
ok: false,
|
|
@@ -799,13 +986,21 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
799
986
|
},
|
|
800
987
|
emitEvent(name, payload) {
|
|
801
988
|
assertMessageName("event", name);
|
|
802
|
-
|
|
803
|
-
|
|
989
|
+
const validatedPayload = parsePayloadWithSchema(options.validation?.events?.[name], payload, {
|
|
990
|
+
name,
|
|
991
|
+
stage: "event.emit"
|
|
992
|
+
});
|
|
993
|
+
assertJsonPayload("event", name, validatedPayload);
|
|
994
|
+
hostServer.emitEvent(name, validatedPayload, options.name);
|
|
804
995
|
},
|
|
805
996
|
broadcast(name, payload) {
|
|
806
997
|
assertMessageName("event", name);
|
|
807
|
-
|
|
808
|
-
|
|
998
|
+
const validatedPayload = parsePayloadWithSchema(options.validation?.events?.[name], payload, {
|
|
999
|
+
name,
|
|
1000
|
+
stage: "event.emit"
|
|
1001
|
+
});
|
|
1002
|
+
assertJsonPayload("event", name, validatedPayload);
|
|
1003
|
+
hostServer.emitEvent(name, validatedPayload, options.name);
|
|
809
1004
|
},
|
|
810
1005
|
close() {
|
|
811
1006
|
return hostServer.close().then(async () => {
|
|
@@ -815,6 +1010,52 @@ function createHostShardwire(options, runtimeHooks) {
|
|
|
815
1010
|
};
|
|
816
1011
|
}
|
|
817
1012
|
|
|
1013
|
+
// src/schema/index.ts
|
|
1014
|
+
function fromSafeParseSchema(schema) {
|
|
1015
|
+
return {
|
|
1016
|
+
parse(value) {
|
|
1017
|
+
const result = schema.safeParse(value);
|
|
1018
|
+
if (result.success) {
|
|
1019
|
+
return result.data;
|
|
1020
|
+
}
|
|
1021
|
+
const error = new Error(result.error.message);
|
|
1022
|
+
if (result.error.issues) {
|
|
1023
|
+
error.issues = result.error.issues;
|
|
1024
|
+
}
|
|
1025
|
+
throw error;
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// src/schema/zod.ts
|
|
1031
|
+
function normalizeZodPath(path) {
|
|
1032
|
+
if (path.length === 0) {
|
|
1033
|
+
return "";
|
|
1034
|
+
}
|
|
1035
|
+
return path.filter((segment) => typeof segment === "string" || typeof segment === "number").map((segment) => String(segment)).join(".");
|
|
1036
|
+
}
|
|
1037
|
+
function fromZodSchema(schema) {
|
|
1038
|
+
return fromSafeParseSchema({
|
|
1039
|
+
safeParse(value) {
|
|
1040
|
+
const result = schema.safeParse(value);
|
|
1041
|
+
if (result.success) {
|
|
1042
|
+
return { success: true, data: result.data };
|
|
1043
|
+
}
|
|
1044
|
+
const issues = result.error.issues.map((issue) => ({
|
|
1045
|
+
path: normalizeZodPath(issue.path),
|
|
1046
|
+
message: issue.message
|
|
1047
|
+
}));
|
|
1048
|
+
return {
|
|
1049
|
+
success: false,
|
|
1050
|
+
error: {
|
|
1051
|
+
message: "Schema validation failed.",
|
|
1052
|
+
issues
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
|
|
818
1059
|
// src/index.ts
|
|
819
1060
|
function isHostOptions(options) {
|
|
820
1061
|
return "server" in options;
|
|
@@ -850,6 +1091,8 @@ function createShardwire(options) {
|
|
|
850
1091
|
}
|
|
851
1092
|
// Annotate the CommonJS export names for ESM import in node:
|
|
852
1093
|
0 && (module.exports = {
|
|
853
|
-
createShardwire
|
|
1094
|
+
createShardwire,
|
|
1095
|
+
fromSafeParseSchema,
|
|
1096
|
+
fromZodSchema
|
|
854
1097
|
});
|
|
855
1098
|
//# sourceMappingURL=index.js.map
|