@objectstack/types 17.0.0-rc.6 → 17.0.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/index.mjs CHANGED
@@ -136,10 +136,25 @@ function _resetEnvDeprecationWarnings() {
136
136
 
137
137
  // src/error-leak.ts
138
138
  var INTERNAL_ERROR_MESSAGE = "Internal server error";
139
+ var DIALECT_LEAK_PHRASINGS = [
140
+ // Postgres 42P01 / 42703 (and, as a superstring, the `… of relation "…"`
141
+ // sub-object family: 42704 and friends). The quotes are required because
142
+ // Postgres always emits them here.
143
+ /\b(?:relation|column)\s+["'`][^"'`]+["'`]\s+does not exist/i,
144
+ // Postgres 42501. Restricted to physical object kinds: `schema`, `view`,
145
+ // `function` and `column` are all ObjectStack AUTHORING vocabulary, so a
146
+ // product message could legitimately use them and a miss is the cheap
147
+ // direction (the outcome is already a 5xx).
148
+ /\bpermission denied for (?:table|relation|sequence|database)\b/i,
149
+ // SQLite/libsql, message-only form. The `sqlite_` limb below catches these
150
+ // only when the driver prefixed its code; `better-sqlite3` and libsql both
151
+ // raise them bare, which is the shape measured across this repo.
152
+ /\bno such (?:table|column):/i
153
+ ];
139
154
  function looksLikeInternalErrorLeak(message) {
140
155
  if (!message) return false;
141
156
  const lower = String(message).toLowerCase();
142
- return lower.includes("sqlite_") || lower.includes("sqlstate") || lower.startsWith("insert into ") || lower.startsWith("update ") || lower.startsWith("select ") || lower.startsWith("delete from ") || lower.includes("constraint failed") || lower.includes("unique constraint") || lower.includes("foreign key");
157
+ return lower.includes("sqlite_") || lower.includes("sqlstate") || lower.startsWith("insert into ") || lower.startsWith("update ") || lower.startsWith("select ") || lower.startsWith("delete from ") || lower.includes("constraint failed") || lower.includes("unique constraint") || lower.includes("foreign key") || DIALECT_LEAK_PHRASINGS.some((pattern) => pattern.test(lower));
143
158
  }
144
159
  function declaresServerFault(err) {
145
160
  if (typeof err !== "object" || err === null) return false;
@@ -224,6 +239,62 @@ function sendError(res, status, code, message, extra) {
224
239
  res.status(status).json({ success: false, error: { code, message, ...extra } });
225
240
  }
226
241
 
242
+ // src/thrown-http-error.ts
243
+ import { ErrorCode, standardErrorCodeForHttpStatus } from "@objectstack/spec/api";
244
+
245
+ // src/validation-failure.ts
246
+ import { zodIssuesToFields } from "@objectstack/spec/api";
247
+ var VALIDATION_FAILED_STATUS = 400;
248
+ function validationFailureDetails(err) {
249
+ if (!err) return void 0;
250
+ if (err.code !== "VALIDATION_FAILED" && err.name !== "ValidationError") return void 0;
251
+ return {
252
+ code: "VALIDATION_FAILED",
253
+ fields: Array.isArray(err.fields) ? err.fields : []
254
+ };
255
+ }
256
+ function validationFailure(message, fields) {
257
+ const err = new Error(message);
258
+ err.name = "ValidationError";
259
+ err.code = "VALIDATION_FAILED";
260
+ err.fields = fields;
261
+ return err;
262
+ }
263
+ function fieldsFromZodIssues(issues, ...input) {
264
+ return zodIssuesToFields(issues, ...input).map(
265
+ (entry) => entry.field === "" ? { ...entry, field: "(body)" } : entry
266
+ );
267
+ }
268
+
269
+ // src/thrown-http-error.ts
270
+ function resolveThrownHttpError(error, fallbackStatus = 500) {
271
+ const e = error;
272
+ const validation = validationFailureDetails(e);
273
+ const declaredStatus = typeof e?.status === "number" ? e.status : typeof e?.statusCode === "number" ? e.statusCode : validation ? VALIDATION_FAILED_STATUS : void 0;
274
+ const status = declaredStatus ?? fallbackStatus;
275
+ const spelled = typeof e?.code === "string" && e.code !== "" ? e.code : void 0;
276
+ const registered = spelled !== void 0 && ErrorCode.safeParse(spelled).success ? spelled : void 0;
277
+ const code = validation ? validation.code : registered ?? standardErrorCodeForHttpStatus(status);
278
+ const declaredCode = validation ? validation.code : spelled;
279
+ const issues = Array.isArray(e?.issues) ? e.issues : void 0;
280
+ const details = {
281
+ // A truthy NON-string `code` (a driver errno, say) is context and stays
282
+ // context — promoting it would put a number in the field callers branch on,
283
+ // which is the drift #3842 removed.
284
+ ...!validation && e?.code && typeof e.code !== "string" ? { code: e.code } : {},
285
+ ...issues ? { issues } : {},
286
+ ...validation ? { fields: validation.fields } : {}
287
+ };
288
+ return {
289
+ status,
290
+ ...declaredStatus !== void 0 ? { declaredStatus } : {},
291
+ code,
292
+ ...declaredCode !== void 0 ? { declaredCode } : {},
293
+ message: typeof e?.message === "string" ? e.message : String(error),
294
+ ...Object.keys(details).length > 0 ? { details } : {}
295
+ };
296
+ }
297
+
227
298
  // src/relation-sub-object.ts
228
299
  function matchMissingColumnOfRelation(message) {
229
300
  return MISSING_COLUMN_OF_RELATION.exec(message)?.[1];
@@ -300,6 +371,23 @@ function uniqueViolationColumn(error) {
300
371
  return findUniqueViolationColumn(error, 0);
301
372
  }
302
373
 
374
+ // src/unbacked-conflict-target.ts
375
+ var UNBACKED_CONFLICT_TARGET = {
376
+ message: /ON CONFLICT clause does not match any PRIMARY KEY or UNIQUE constraint|there is no unique or exclusion constraint matching the ON CONFLICT specification/i
377
+ };
378
+ var MAX_CAUSE_DEPTH2 = 4;
379
+ function isUnbackedConflictTargetError(error) {
380
+ return matchesUnbackedConflictTarget(error, 0);
381
+ }
382
+ function matchesUnbackedConflictTarget(error, depth) {
383
+ if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH2) return false;
384
+ if (typeof error === "string") return UNBACKED_CONFLICT_TARGET.message.test(error);
385
+ if (typeof error !== "object") return false;
386
+ const err = error;
387
+ if (typeof err.message === "string" && UNBACKED_CONFLICT_TARGET.message.test(err.message)) return true;
388
+ return matchesUnbackedConflictTarget(err.cause, depth + 1);
389
+ }
390
+
303
391
  // src/unique-scope-install-gate.ts
304
392
  import { normalizeTenancyPosture as normalizeTenancyPosture2 } from "@objectstack/spec/security";
305
393
  var SYS_OBJECT_PREFIXES = ["sys_", "base_"];
@@ -401,6 +489,7 @@ export {
401
489
  GLOBAL_UNIQUE_CONFIRMATION_REQUIRED,
402
490
  GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION,
403
491
  INTERNAL_ERROR_MESSAGE,
492
+ VALIDATION_FAILED_STATUS,
404
493
  _resetEnvDeprecationWarnings,
405
494
  buildGlobalUniqueStopMessage,
406
495
  collectConfiguredLocales,
@@ -410,11 +499,13 @@ export {
410
499
  describeGlobalUniqueFinding,
411
500
  emitDegradedBootBanner,
412
501
  fieldUniqueIsGlobal,
502
+ fieldsFromZodIssues,
413
503
  globalUniqueFindingId,
414
504
  isMcpServerEnabled,
415
505
  isModuleNotFoundError,
416
506
  isPlatformOwnedObject,
417
507
  isRelationSubObjectPhrase,
508
+ isUnbackedConflictTargetError,
418
509
  isUniqueViolationError,
419
510
  keysetWalk,
420
511
  looksLikeInternalErrorLeak,
@@ -431,10 +522,13 @@ export {
431
522
  resolveSandboxTimeoutMs,
432
523
  resolveSearchPinyinEnabled,
433
524
  resolveTenancyPosture,
525
+ resolveThrownHttpError,
434
526
  sendError,
435
527
  sendOk,
436
528
  stampSearchPinyinEnabled,
437
529
  unconfirmedGlobalUniques,
438
- uniqueViolationColumn
530
+ uniqueViolationColumn,
531
+ validationFailure,
532
+ validationFailureDetails
439
533
  };
440
534
  //# sourceMappingURL=index.mjs.map