@vibeorm/runtime 1.3.0 → 2.0.0-alpha.10

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.
Files changed (96) hide show
  1. package/README.md +50 -107
  2. package/dist/adapter.d.ts +250 -0
  3. package/dist/adapter.d.ts.map +1 -0
  4. package/dist/bulk-upsert.d.ts +282 -0
  5. package/dist/bulk-upsert.d.ts.map +1 -0
  6. package/dist/client.d.ts +200 -0
  7. package/dist/client.d.ts.map +1 -0
  8. package/dist/codecs.d.ts +170 -0
  9. package/dist/codecs.d.ts.map +1 -0
  10. package/dist/computed.d.ts +43 -0
  11. package/dist/computed.d.ts.map +1 -0
  12. package/dist/db-now.d.ts +41 -0
  13. package/dist/db-now.d.ts.map +1 -0
  14. package/dist/diagnostics/index.d.ts +12 -0
  15. package/dist/diagnostics/index.d.ts.map +1 -0
  16. package/dist/diagnostics/insight.d.ts +63 -0
  17. package/dist/diagnostics/insight.d.ts.map +1 -0
  18. package/dist/diagnostics/plan.d.ts +88 -0
  19. package/dist/diagnostics/plan.d.ts.map +1 -0
  20. package/dist/diagnostics/preview.d.ts +43 -0
  21. package/dist/diagnostics/preview.d.ts.map +1 -0
  22. package/dist/diagnostics/types.d.ts +223 -0
  23. package/dist/diagnostics/types.d.ts.map +1 -0
  24. package/dist/diagnostics/workload.d.ts +32 -0
  25. package/dist/diagnostics/workload.d.ts.map +1 -0
  26. package/dist/extensions.d.ts +102 -0
  27. package/dist/extensions.d.ts.map +1 -0
  28. package/dist/index.d.ts +59 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +13070 -0
  31. package/dist/index.js.map +43 -0
  32. package/dist/keyset-iterator.d.ts +73 -0
  33. package/dist/keyset-iterator.d.ts.map +1 -0
  34. package/dist/keyset.d.ts +121 -0
  35. package/dist/keyset.d.ts.map +1 -0
  36. package/dist/model-meta.d.ts +200 -0
  37. package/dist/model-meta.d.ts.map +1 -0
  38. package/dist/nested-writes.d.ts +67 -0
  39. package/dist/nested-writes.d.ts.map +1 -0
  40. package/dist/policy-operation.d.ts +14 -0
  41. package/dist/policy-operation.d.ts.map +1 -0
  42. package/dist/policy.d.ts +17 -0
  43. package/dist/policy.d.ts.map +1 -0
  44. package/dist/query-builder.d.ts +271 -0
  45. package/dist/query-builder.d.ts.map +1 -0
  46. package/dist/relation-key.d.ts +23 -0
  47. package/dist/relation-key.d.ts.map +1 -0
  48. package/dist/relation-loader.d.ts +46 -0
  49. package/dist/relation-loader.d.ts.map +1 -0
  50. package/dist/relation-plan.d.ts +141 -0
  51. package/dist/relation-plan.d.ts.map +1 -0
  52. package/dist/render-cache.d.ts +48 -0
  53. package/dist/render-cache.d.ts.map +1 -0
  54. package/dist/rls-context.d.ts +14 -0
  55. package/dist/rls-context.d.ts.map +1 -0
  56. package/dist/rls-readiness.d.ts +114 -0
  57. package/dist/rls-readiness.d.ts.map +1 -0
  58. package/dist/scoped.d.ts +104 -0
  59. package/dist/scoped.d.ts.map +1 -0
  60. package/dist/strict-args.d.ts +47 -0
  61. package/dist/strict-args.d.ts.map +1 -0
  62. package/dist/telemetry/collector.d.ts +53 -0
  63. package/dist/telemetry/collector.d.ts.map +1 -0
  64. package/dist/telemetry/config.d.ts +53 -0
  65. package/dist/telemetry/config.d.ts.map +1 -0
  66. package/dist/telemetry/fingerprint.d.ts +38 -0
  67. package/dist/telemetry/fingerprint.d.ts.map +1 -0
  68. package/dist/telemetry/index.d.ts +18 -0
  69. package/dist/telemetry/index.d.ts.map +1 -0
  70. package/dist/telemetry/recorder.d.ts +93 -0
  71. package/dist/telemetry/recorder.d.ts.map +1 -0
  72. package/dist/telemetry/statement.d.ts +53 -0
  73. package/dist/telemetry/statement.d.ts.map +1 -0
  74. package/dist/telemetry/types.d.ts +265 -0
  75. package/dist/telemetry/types.d.ts.map +1 -0
  76. package/dist/validators.d.ts +61 -0
  77. package/dist/validators.d.ts.map +1 -0
  78. package/dist/views.d.ts +97 -0
  79. package/dist/views.d.ts.map +1 -0
  80. package/dist/write-scope.d.ts +14 -0
  81. package/dist/write-scope.d.ts.map +1 -0
  82. package/package.json +33 -26
  83. package/src/adapter.ts +0 -146
  84. package/src/client.ts +0 -2172
  85. package/src/coerce.ts +0 -184
  86. package/src/count-loader.ts +0 -152
  87. package/src/errors.ts +0 -492
  88. package/src/id-generators.ts +0 -151
  89. package/src/index.ts +0 -55
  90. package/src/lateral-join-builder.ts +0 -1053
  91. package/src/query-builder.ts +0 -1832
  92. package/src/relation-loader.ts +0 -534
  93. package/src/retry.ts +0 -183
  94. package/src/types.ts +0 -317
  95. package/src/view.ts +0 -629
  96. package/src/where-builder.ts +0 -772
package/src/errors.ts DELETED
@@ -1,492 +0,0 @@
1
- /**
2
- * VibeORM Error Hierarchy
3
- *
4
- * All VibeORM errors extend the abstract VibeError base class, split into
5
- * two concrete branches:
6
- *
7
- * - VibeRequestError — deterministic failures caused by invalid data or
8
- * violated constraints. Running the same operation again will produce
9
- * the same error. Includes: unique constraint, FK violation, not-null,
10
- * check constraint, not-found, and validation errors.
11
- *
12
- * - VibeTransientError — transient infrastructure failures where retrying
13
- * the same operation may succeed. Includes: connection errors, deadlocks,
14
- * serialization failures, statement timeouts, and pool exhaustion.
15
- *
16
- * VibeValidationError (Zod validation) is a subclass of VibeRequestError,
17
- * so `instanceof VibeRequestError` catches both constraint violations AND
18
- * validation errors. Use `instanceof VibeValidationError` to narrow.
19
- *
20
- * @example
21
- * ```ts
22
- * import { VibeRequestError, VibeTransientError, VibeError } from "@vibeorm/runtime";
23
- *
24
- * try {
25
- * await db.user.create({ data: { email: "taken@example.com" } });
26
- * } catch (error) {
27
- * if (error instanceof VibeRequestError) {
28
- * if (error.code === "UNIQUE_CONSTRAINT") {
29
- * console.log(error.meta.constraint); // "User_email_key"
30
- * console.log(error.meta.detail); // 'Key (email)=(taken@example.com) already exists.'
31
- * return { error: "Email already taken" };
32
- * }
33
- * }
34
- * if (error instanceof VibeTransientError) {
35
- * // error.retryable is always true
36
- * return retry(() => db.user.create({ ... }));
37
- * }
38
- * throw error;
39
- * }
40
- * ```
41
- */
42
-
43
- // ─── Error Codes ─────────────────────────────────────────────────
44
-
45
- /**
46
- * Error codes for deterministic request failures.
47
- * The operation itself is invalid — changing the data would fix it.
48
- */
49
- export type VibeRequestErrorCode =
50
- | "UNIQUE_CONSTRAINT"
51
- | "FOREIGN_KEY_VIOLATION"
52
- | "NOT_NULL_VIOLATION"
53
- | "CHECK_CONSTRAINT"
54
- | "VALUE_OUT_OF_RANGE"
55
- | "NOT_FOUND"
56
- | "VALIDATION_ERROR"
57
- | "UNKNOWN_REQUEST_ERROR";
58
-
59
- /**
60
- * Error codes for transient infrastructure failures.
61
- * The operation is valid but the infrastructure failed — retrying may fix it.
62
- */
63
- export type VibeTransientErrorCode =
64
- | "CONNECTION_ERROR"
65
- | "DEADLOCK"
66
- | "SERIALIZATION_FAILURE"
67
- | "STATEMENT_TIMEOUT"
68
- | "TOO_MANY_CONNECTIONS"
69
- | "UNKNOWN_TRANSIENT_ERROR";
70
-
71
- /** Union of all VibeORM error codes. */
72
- export type VibeErrorCode = VibeRequestErrorCode | VibeTransientErrorCode;
73
-
74
- // ─── Error Meta ──────────────────────────────────────────────────
75
-
76
- /**
77
- * Structured metadata attached to every VibeORM error.
78
- * Fields are populated when available from the PostgreSQL error protocol
79
- * or from the application-level context (model name, operation, etc.).
80
- */
81
- export type VibeErrorMeta = {
82
- /** VibeORM model name (e.g. "User", "Post"). Set for app-level errors. */
83
- model?: string;
84
- /** The field that caused the error (extracted from PG detail when possible). */
85
- field?: string;
86
- /** PostgreSQL constraint name (e.g. "User_email_key"). */
87
- constraint?: string;
88
- /** PostgreSQL table name from the error (e.g. "User"). */
89
- table?: string;
90
- /** PostgreSQL column name from the error. */
91
- column?: string;
92
- /** PostgreSQL schema name from the error (e.g. "public"). */
93
- schema?: string;
94
- /** Human-readable detail from PostgreSQL (e.g. 'Key (email)=(x@y.com) already exists.'). */
95
- detail?: string;
96
- /** The VibeORM operation that triggered this error (e.g. "create", "update"). */
97
- operation?: string;
98
- /** Validation direction — only set on VibeValidationError. */
99
- direction?: "input" | "output";
100
- /** Raw Zod error object — only set on VibeValidationError. */
101
- zodError?: unknown;
102
- };
103
-
104
- // ─── Base Class ──────────────────────────────────────────────────
105
-
106
- /**
107
- * Abstract base class for all VibeORM errors.
108
- * Use `instanceof VibeError` to catch any error originating from VibeORM.
109
- */
110
- export abstract class VibeError extends Error {
111
- abstract readonly code: VibeErrorCode;
112
- readonly meta: VibeErrorMeta;
113
-
114
- constructor(params: { message: string; meta?: VibeErrorMeta; cause?: Error }) {
115
- super(params.message, { cause: params.cause });
116
- this.name = "VibeError";
117
- this.meta = params.meta ?? {};
118
- }
119
- }
120
-
121
- // ─── Request Error (deterministic) ──────────────────────────────
122
-
123
- /**
124
- * Deterministic request error — the operation itself is invalid.
125
- * Same input will always produce the same failure.
126
- *
127
- * Covers: constraint violations, not-found, validation, and
128
- * unrecognized database errors that aren't transient.
129
- *
130
- * Use `error.code` to narrow the specific failure type.
131
- */
132
- export class VibeRequestError extends VibeError {
133
- readonly code: VibeRequestErrorCode;
134
-
135
- constructor(params: {
136
- code: VibeRequestErrorCode;
137
- message: string;
138
- meta?: VibeErrorMeta;
139
- cause?: Error;
140
- }) {
141
- super({ message: params.message, meta: params.meta, cause: params.cause });
142
- this.name = "VibeRequestError";
143
- this.code = params.code;
144
- }
145
- }
146
-
147
- // ─── Validation Error (subclass of Request) ─────────────────────
148
-
149
- /**
150
- * Zod validation error — thrown when input or output data fails schema validation.
151
- *
152
- * Subclass of VibeRequestError, so `instanceof VibeRequestError` catches it.
153
- * Use `instanceof VibeValidationError` to narrow specifically to validation failures.
154
- *
155
- * Preserves backward-compatible fields: model, operation, direction, zodError.
156
- */
157
- export class VibeValidationError extends VibeRequestError {
158
- readonly model: string;
159
- readonly operation: string;
160
- readonly direction: "input" | "output";
161
- readonly zodError: unknown;
162
-
163
- constructor(params: {
164
- model: string;
165
- operation: string;
166
- direction: "input" | "output";
167
- zodError: unknown;
168
- }) {
169
- const { model, operation, direction, zodError } = params;
170
- const msg = `Validation failed for ${model}.${operation} (${direction}): ${formatZodError({ error: zodError })}`;
171
- super({
172
- code: "VALIDATION_ERROR",
173
- message: msg,
174
- meta: { model, operation, direction, zodError },
175
- });
176
- this.name = "VibeValidationError";
177
- this.model = model;
178
- this.operation = operation;
179
- this.direction = direction;
180
- this.zodError = zodError;
181
- }
182
- }
183
-
184
- // ─── Transient Error (retryable) ────────────────────────────────
185
-
186
- /**
187
- * Transient infrastructure error — the operation is valid but the
188
- * infrastructure failed. Retrying the same operation may succeed.
189
- *
190
- * Covers: connection errors, deadlocks, serialization failures,
191
- * statement timeouts, and pool exhaustion.
192
- *
193
- * `retryable` is always `true` on this class.
194
- */
195
- export class VibeTransientError extends VibeError {
196
- readonly code: VibeTransientErrorCode;
197
- readonly retryable = true as const;
198
-
199
- constructor(params: {
200
- code: VibeTransientErrorCode;
201
- message: string;
202
- meta?: VibeErrorMeta;
203
- cause?: Error;
204
- }) {
205
- super({ message: params.message, meta: params.meta, cause: params.cause });
206
- this.name = "VibeTransientError";
207
- this.code = params.code;
208
- }
209
- }
210
-
211
- // ─── SQLSTATE → VibeError Mapping ───────────────────────────────
212
-
213
- /**
214
- * SQLSTATE code ranges for transient (retryable) errors.
215
- * Class 08 = connection, Class 40 = transaction rollback,
216
- * 57014 = query_canceled (statement_timeout), 53300 = too_many_connections.
217
- */
218
- const TRANSIENT_CODE_MAP: Record<string, VibeTransientErrorCode> = {
219
- "08000": "CONNECTION_ERROR",
220
- "08001": "CONNECTION_ERROR",
221
- "08003": "CONNECTION_ERROR",
222
- "08004": "CONNECTION_ERROR",
223
- "08006": "CONNECTION_ERROR",
224
- "08007": "CONNECTION_ERROR",
225
- "08P01": "CONNECTION_ERROR",
226
- "40P01": "DEADLOCK",
227
- "40001": "SERIALIZATION_FAILURE",
228
- "57014": "STATEMENT_TIMEOUT",
229
- "53300": "TOO_MANY_CONNECTIONS",
230
- };
231
-
232
- /**
233
- * SQLSTATE codes for constraint violation errors (Class 23).
234
- */
235
- const CONSTRAINT_CODE_MAP: Record<string, VibeRequestErrorCode> = {
236
- "23505": "UNIQUE_CONSTRAINT",
237
- "23503": "FOREIGN_KEY_VIOLATION",
238
- "23502": "NOT_NULL_VIOLATION",
239
- "23514": "CHECK_CONSTRAINT",
240
- };
241
-
242
- /**
243
- * SQLSTATE Class 22 — data exception. We map the specific codes we want to
244
- * surface as actionable errors. 22003 is the canonical "value out of range
245
- * for type" code; the most common way users hit it is inserting a `BigInt`
246
- * value larger than 2^63-1 into a `bigint` column (Bug 9).
247
- */
248
- const DATA_EXCEPTION_CODE_MAP: Record<string, VibeRequestErrorCode> = {
249
- "22003": "VALUE_OUT_OF_RANGE",
250
- };
251
-
252
- /**
253
- * Extract a field name from a PostgreSQL detail string.
254
- *
255
- * Examples:
256
- * - 'Key (email)=(x@y.com) already exists.' → "email"
257
- * - 'Failing row contains (1, null, ...).' → undefined
258
- * - 'Key (author_id)=(999) is not present in table "User".' → "author_id"
259
- */
260
- function extractFieldFromDetail(params: { detail: string }): string | undefined {
261
- const match = params.detail.match(/Key \(([^)]+)\)/);
262
- return match ? match[1] : undefined;
263
- }
264
-
265
- /**
266
- * Shape of a PostgreSQL protocol error as exposed by both bun:sql and node-postgres.
267
- *
268
- * Note: bun:sql puts the SQLSTATE code in `errno` (e.g. "23505") while `code`
269
- * contains a Node.js-style string (e.g. "ERR_POSTGRES_SERVER_ERROR").
270
- * node-postgres puts the SQLSTATE code in `code` directly.
271
- */
272
- type PgProtocolError = {
273
- code: string;
274
- errno?: string;
275
- message: string;
276
- detail?: string;
277
- hint?: string;
278
- constraint?: string;
279
- table?: string;
280
- column?: string | number;
281
- schema?: string;
282
- severity?: string;
283
- };
284
-
285
- /**
286
- * Check whether a raw error object looks like a PostgreSQL protocol error.
287
- * Both bun:sql (PostgresError) and node-postgres (DatabaseError) expose
288
- * error fields from the PostgreSQL wire protocol. The SQLSTATE code is in
289
- * `errno` (bun:sql) or `code` (node-postgres).
290
- */
291
- function isPgError(error: unknown): error is PgProtocolError {
292
- if (error === null || typeof error !== "object" || !("message" in error)) return false;
293
- const e = error as Record<string, unknown>;
294
- // node-postgres: has `code` as a 5-char SQLSTATE string
295
- // bun:sql: has `errno` as a SQLSTATE string + `severity`
296
- return (
297
- (typeof e.code === "string" && /^[0-9A-Z]{5}$/.test(e.code)) ||
298
- (typeof e.errno === "string" && typeof e.severity === "string")
299
- );
300
- }
301
-
302
- /**
303
- * Extract the SQLSTATE code from a PgProtocolError.
304
- * bun:sql stores it in `errno`, node-postgres stores it in `code`.
305
- */
306
- function getSqlStateCode(error: PgProtocolError): string {
307
- // bun:sql: errno contains the actual SQLSTATE code (e.g. "23505")
308
- if (error.errno && /^[0-9A-Z]{5}$/.test(error.errno)) {
309
- return error.errno;
310
- }
311
- // node-postgres: code contains the SQLSTATE code
312
- if (/^[0-9A-Z]{5}$/.test(error.code)) {
313
- return error.code;
314
- }
315
- return error.code;
316
- }
317
-
318
- /**
319
- * Check whether a raw error looks like a client-side connection error
320
- * (e.g. ECONNREFUSED, ENOTFOUND, ETIMEDOUT) that doesn't have a SQLSTATE code.
321
- */
322
- function isConnectionError(err: unknown): boolean {
323
- if (err === null || typeof err !== "object") return false;
324
- const anyErr = err as Record<string, unknown>;
325
-
326
- // Node.js system errors from net/dns
327
- if (typeof anyErr.code === "string") {
328
- const code = anyErr.code;
329
- if (
330
- code === "ECONNREFUSED" ||
331
- code === "ECONNRESET" ||
332
- code === "ENOTFOUND" ||
333
- code === "ETIMEDOUT" ||
334
- code === "EPIPE"
335
- ) {
336
- return true;
337
- }
338
- }
339
-
340
- // bun:sql connection-level errors often have specific message patterns
341
- const msg = typeof anyErr.message === "string" ? anyErr.message : "";
342
- if (
343
- msg.includes("connection refused") ||
344
- msg.includes("Connection terminated") ||
345
- msg.includes("Connection lost") ||
346
- msg.includes("connect ECONNREFUSED") ||
347
- msg.includes("the database system is starting up")
348
- ) {
349
- return true;
350
- }
351
-
352
- return false;
353
- }
354
-
355
- /**
356
- * Normalize a raw database error into a structured VibeORM error.
357
- *
358
- * Both bun:sql and node-postgres expose the PostgreSQL ErrorResponse fields
359
- * (code, detail, constraint, table, column, schema, severity), so this
360
- * function is adapter-agnostic.
361
- *
362
- * If the error is already a VibeError, it is returned as-is.
363
- *
364
- * @param error - The raw error from the database driver.
365
- * @param model - Optional VibeORM model name for context.
366
- * @param operation - Optional operation name for context.
367
- */
368
- export function normalizeError(params: {
369
- error: unknown;
370
- model?: string;
371
- operation?: string;
372
- }): VibeRequestError | VibeTransientError {
373
- const { error, model, operation } = params;
374
-
375
- // Already a VibeError — return as-is (don't double-wrap)
376
- if (error instanceof VibeError) {
377
- return error as VibeRequestError | VibeTransientError;
378
- }
379
-
380
- const cause = error instanceof Error ? error : new Error(String(error));
381
-
382
- // ─── PostgreSQL protocol error (has SQLSTATE code) ───────────
383
- if (isPgError(error)) {
384
- const pgErr = error;
385
- const pgCode = getSqlStateCode(pgErr);
386
- const meta: VibeErrorMeta = {
387
- model,
388
- operation,
389
- constraint: pgErr.constraint,
390
- table: pgErr.table,
391
- column: typeof pgErr.column === "string" ? pgErr.column : undefined,
392
- schema: pgErr.schema,
393
- detail: pgErr.detail,
394
- };
395
-
396
- // Extract field name from detail when available
397
- if (pgErr.detail) {
398
- const field = extractFieldFromDetail({ detail: pgErr.detail });
399
- if (field) meta.field = field;
400
- }
401
-
402
- // Check transient errors first (Class 08, 40, 57014, 53300)
403
- const transientCode = TRANSIENT_CODE_MAP[pgCode];
404
- if (transientCode) {
405
- return new VibeTransientError({
406
- code: transientCode,
407
- message: pgErr.message,
408
- meta,
409
- cause,
410
- });
411
- }
412
-
413
- // Check constraint violations (Class 23)
414
- const constraintCode = CONSTRAINT_CODE_MAP[pgCode];
415
- if (constraintCode) {
416
- return new VibeRequestError({
417
- code: constraintCode,
418
- message: pgErr.message,
419
- meta,
420
- cause,
421
- });
422
- }
423
-
424
- // Data exception (Class 22): e.g. value out of range for the column type.
425
- // Specifically: 22003 is what users see when a BigInt value overflows the
426
- // signed-int64 limit on a `bigint` column. We surface a targeted hint for
427
- // that case because the raw PG message ("value out of range for type
428
- // bigint") is easy to misread as a driver bug. Bug 9.
429
- const dataExceptionCode = DATA_EXCEPTION_CODE_MAP[pgCode];
430
- if (dataExceptionCode) {
431
- const isBigIntRange =
432
- dataExceptionCode === "VALUE_OUT_OF_RANGE" &&
433
- /out of range for type bigint/i.test(pgErr.message);
434
- const message = isBigIntRange
435
- ? `${pgErr.message} (PostgreSQL bigint is signed int64, max 0x7fffffffffffffff = 2^63-1. For unsigned 64-bit values, store as String or Decimal.)`
436
- : pgErr.message;
437
- return new VibeRequestError({
438
- code: dataExceptionCode,
439
- message,
440
- meta,
441
- cause,
442
- });
443
- }
444
-
445
- // Check transient by SQLSTATE class prefix
446
- if (pgCode.startsWith("08") || pgCode.startsWith("40")) {
447
- return new VibeTransientError({
448
- code: pgCode.startsWith("08") ? "CONNECTION_ERROR" : "UNKNOWN_TRANSIENT_ERROR",
449
- message: pgErr.message,
450
- meta,
451
- cause,
452
- });
453
- }
454
-
455
- // Unrecognized SQLSTATE — treat as request error
456
- return new VibeRequestError({
457
- code: "UNKNOWN_REQUEST_ERROR",
458
- message: pgErr.message,
459
- meta,
460
- cause,
461
- });
462
- }
463
-
464
- // ─── Client-side connection error (no SQLSTATE) ──────────────
465
- if (isConnectionError(error)) {
466
- return new VibeTransientError({
467
- code: "CONNECTION_ERROR",
468
- message: cause.message,
469
- meta: { model, operation },
470
- cause,
471
- });
472
- }
473
-
474
- // ─── Unknown error — treat as request error ──────────────────
475
- return new VibeRequestError({
476
- code: "UNKNOWN_REQUEST_ERROR",
477
- message: cause.message,
478
- meta: { model, operation },
479
- cause,
480
- });
481
- }
482
-
483
- // ─── Helpers ─────────────────────────────────────────────────────
484
-
485
- function formatZodError(params: { error: unknown }): string {
486
- const { error } = params;
487
- if (error && typeof error === "object" && "issues" in error) {
488
- const issues = (error as { issues: Array<{ path: (string | number)[]; message: string }> }).issues;
489
- return issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
490
- }
491
- return String(error);
492
- }
@@ -1,151 +0,0 @@
1
- /**
2
- * Zero-dependency, cryptographically secure ID generators.
3
- *
4
- * Used by the runtime to auto-generate values for fields with
5
- * @default(uuid()), @default(cuid()), @default(nanoid()), @default(ulid()).
6
- *
7
- * All implementations use crypto.getRandomValues() for security.
8
- */
9
-
10
- // ─── UUID v4 ──────────────────────────────────────────────────────
11
-
12
- /**
13
- * Generate a UUID v4 string.
14
- * Uses crypto.randomUUID() when available (Node 19+, Bun, Deno, browsers),
15
- * falls back to a manual implementation.
16
- */
17
- export function generateUuid(): string {
18
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
19
- return crypto.randomUUID();
20
- }
21
- // Manual fallback using crypto.getRandomValues
22
- const bytes = new Uint8Array(16);
23
- crypto.getRandomValues(bytes);
24
- // Set version (4) and variant (RFC 4122)
25
- bytes[6] = (bytes[6]! & 0x0f) | 0x40;
26
- bytes[8] = (bytes[8]! & 0x3f) | 0x80;
27
- const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
28
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
29
- }
30
-
31
- // ─── CUID2 ────────────────────────────────────────────────────────
32
-
33
- /**
34
- * Generate a CUID2-compatible string.
35
- *
36
- * CUID2 is a secure, collision-resistant ID optimized for horizontal scaling.
37
- * This is a simplified implementation that produces IDs with the same properties:
38
- * - Starts with a letter (for HTML element IDs and DB compatibility)
39
- * - 24 characters long (default CUID2 length)
40
- * - Cryptographically random
41
- *
42
- * Uses a base-36 encoding of random bytes with a letter prefix.
43
- */
44
- const CUID_LENGTH = 24;
45
- const CUID_ALPHABET = "abcdefghijklmnopqrstuvwxyz";
46
-
47
- export function generateCuid(): string {
48
- // First char is always a letter
49
- const firstByte = new Uint8Array(1);
50
- crypto.getRandomValues(firstByte);
51
- const prefix = CUID_ALPHABET[firstByte[0]! % 26]!;
52
-
53
- // Remaining chars from random bytes encoded as base36
54
- // We need enough random bytes to produce CUID_LENGTH - 1 base36 chars
55
- // Each byte gives ~1.29 base36 chars, so we need ceil((CUID_LENGTH-1)/1.29) ≈ 18 bytes
56
- const bytes = new Uint8Array(32);
57
- crypto.getRandomValues(bytes);
58
-
59
- let result = prefix;
60
- // Convert bytes to a big number string in base36
61
- let carry = 0n;
62
- for (let i = 0; i < bytes.length; i++) {
63
- carry = (carry << 8n) | BigInt(bytes[i]!);
64
- }
65
- const base36 = carry.toString(36);
66
- result += base36.slice(0, CUID_LENGTH - 1).padStart(CUID_LENGTH - 1, "a");
67
-
68
- return result;
69
- }
70
-
71
- // ─── NanoID ───────────────────────────────────────────────────────
72
-
73
- /**
74
- * Generate a NanoID-compatible string.
75
- *
76
- * NanoID uses a URL-safe alphabet (A-Za-z0-9_-) and produces 21-character IDs.
77
- * This is a high-performance implementation using bit masking for uniform distribution.
78
- */
79
- const NANOID_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
80
- const NANOID_LENGTH = 21;
81
- const NANOID_MASK = 63; // 0x3F — 6 bits, matching alphabet size of 64
82
-
83
- export function generateNanoid(): string {
84
- const bytes = new Uint8Array(NANOID_LENGTH);
85
- crypto.getRandomValues(bytes);
86
-
87
- let id = "";
88
- for (let i = 0; i < NANOID_LENGTH; i++) {
89
- id += NANOID_ALPHABET[bytes[i]! & NANOID_MASK]!;
90
- }
91
- return id;
92
- }
93
-
94
- // ─── ULID ─────────────────────────────────────────────────────────
95
-
96
- /**
97
- * Generate a ULID (Universally Unique Lexicographically Sortable Identifier).
98
- *
99
- * Format: 10 chars timestamp (48-bit ms since epoch) + 16 chars randomness (80-bit)
100
- * Encoding: Crockford's Base32 (0-9A-HJKMNP-TV-Z)
101
- * Total: 26 characters, lexicographically sortable by creation time.
102
- */
103
- const ULID_ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
104
- const ULID_ENCODING_LEN = 32;
105
-
106
- function encodeTime(params: { now: number; len: number }): string {
107
- let { now, len } = params;
108
- let str = "";
109
- for (; len > 0; len--) {
110
- str = ULID_ENCODING[now % ULID_ENCODING_LEN]! + str;
111
- now = Math.floor(now / ULID_ENCODING_LEN);
112
- }
113
- return str;
114
- }
115
-
116
- function encodeRandom(params: { len: number }): string {
117
- const { len } = params;
118
- const bytes = new Uint8Array(len);
119
- crypto.getRandomValues(bytes);
120
- let str = "";
121
- for (let i = 0; i < len; i++) {
122
- str += ULID_ENCODING[bytes[i]! % ULID_ENCODING_LEN]!;
123
- }
124
- return str;
125
- }
126
-
127
- export function generateUlid(): string {
128
- const now = Date.now();
129
- return encodeTime({ now, len: 10 }) + encodeRandom({ len: 16 });
130
- }
131
-
132
- // ─── Dispatcher ───────────────────────────────────────────────────
133
-
134
- /**
135
- * Generate an ID value based on the default kind.
136
- * Returns undefined for kinds that are handled at the DB level (autoincrement, now, literal).
137
- */
138
- export function generateDefault(params: { kind: string }): string | undefined {
139
- switch (params.kind) {
140
- case "uuid":
141
- return generateUuid();
142
- case "cuid":
143
- return generateCuid();
144
- case "nanoid":
145
- return generateNanoid();
146
- case "ulid":
147
- return generateUlid();
148
- default:
149
- return undefined;
150
- }
151
- }
package/src/index.ts DELETED
@@ -1,55 +0,0 @@
1
- /**
2
- * @vibeorm/runtime — Driver-agnostic VibeORM client runtime.
3
- *
4
- * This package contains the core query engine, SQL builders, and relation
5
- * loading strategies. It does NOT include any database driver — use one
6
- * of the adapter packages (@vibeorm/adapter-bun, @vibeorm/adapter-pg)
7
- * to connect to PostgreSQL.
8
- */
9
-
10
- export { createClient } from "./client.ts";
11
- export {
12
- VibeError,
13
- VibeRequestError,
14
- VibeTransientError,
15
- VibeValidationError,
16
- normalizeError,
17
- } from "./errors.ts";
18
- export {
19
- loadRelationsWithLateralJoin,
20
- executeLateralJoinQuery,
21
- } from "./lateral-join-builder.ts";
22
- export { toSqlExecutor } from "./adapter.ts";
23
- export { withRetry } from "./retry.ts";
24
- export { ViewResult, createView } from "./view.ts";
25
- export type { ViewDefinition } from "./view.ts";
26
- export type { RetryOptions } from "./retry.ts";
27
- export { PgArray } from "./types.ts";
28
-
29
- export type {
30
- DatabaseAdapter,
31
- QueryResult,
32
- SqlExecutor,
33
- TransactionOptions,
34
- } from "./adapter.ts";
35
-
36
- export type {
37
- VibeErrorCode,
38
- VibeRequestErrorCode,
39
- VibeTransientErrorCode,
40
- VibeErrorMeta,
41
- } from "./errors.ts";
42
-
43
- export type {
44
- VibeClientOptions,
45
- ModelMeta,
46
- ModelMetaMap,
47
- ModelSchemas,
48
- ValidationSchema,
49
- QueryProfile,
50
- RelationProfile,
51
- ScalarFieldMeta,
52
- RelationFieldMeta,
53
- SqlQuery,
54
- Operation,
55
- } from "./types.ts";