@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.js CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  GLOBAL_UNIQUE_CONFIRMATION_REQUIRED: () => GLOBAL_UNIQUE_CONFIRMATION_REQUIRED,
24
24
  GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION: () => GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION,
25
25
  INTERNAL_ERROR_MESSAGE: () => INTERNAL_ERROR_MESSAGE,
26
+ VALIDATION_FAILED_STATUS: () => VALIDATION_FAILED_STATUS,
26
27
  _resetEnvDeprecationWarnings: () => _resetEnvDeprecationWarnings,
27
28
  buildGlobalUniqueStopMessage: () => buildGlobalUniqueStopMessage,
28
29
  collectConfiguredLocales: () => collectConfiguredLocales,
@@ -32,11 +33,13 @@ __export(index_exports, {
32
33
  describeGlobalUniqueFinding: () => describeGlobalUniqueFinding,
33
34
  emitDegradedBootBanner: () => emitDegradedBootBanner,
34
35
  fieldUniqueIsGlobal: () => fieldUniqueIsGlobal,
36
+ fieldsFromZodIssues: () => fieldsFromZodIssues,
35
37
  globalUniqueFindingId: () => globalUniqueFindingId,
36
38
  isMcpServerEnabled: () => isMcpServerEnabled,
37
39
  isModuleNotFoundError: () => isModuleNotFoundError,
38
40
  isPlatformOwnedObject: () => isPlatformOwnedObject,
39
41
  isRelationSubObjectPhrase: () => isRelationSubObjectPhrase,
42
+ isUnbackedConflictTargetError: () => isUnbackedConflictTargetError,
40
43
  isUniqueViolationError: () => isUniqueViolationError,
41
44
  keysetWalk: () => keysetWalk,
42
45
  looksLikeInternalErrorLeak: () => looksLikeInternalErrorLeak,
@@ -53,11 +56,14 @@ __export(index_exports, {
53
56
  resolveSandboxTimeoutMs: () => resolveSandboxTimeoutMs,
54
57
  resolveSearchPinyinEnabled: () => resolveSearchPinyinEnabled,
55
58
  resolveTenancyPosture: () => resolveTenancyPosture,
59
+ resolveThrownHttpError: () => resolveThrownHttpError,
56
60
  sendError: () => sendError,
57
61
  sendOk: () => sendOk,
58
62
  stampSearchPinyinEnabled: () => stampSearchPinyinEnabled,
59
63
  unconfirmedGlobalUniques: () => unconfirmedGlobalUniques,
60
- uniqueViolationColumn: () => uniqueViolationColumn
64
+ uniqueViolationColumn: () => uniqueViolationColumn,
65
+ validationFailure: () => validationFailure,
66
+ validationFailureDetails: () => validationFailureDetails
61
67
  });
62
68
  module.exports = __toCommonJS(index_exports);
63
69
 
@@ -196,10 +202,25 @@ function _resetEnvDeprecationWarnings() {
196
202
 
197
203
  // src/error-leak.ts
198
204
  var INTERNAL_ERROR_MESSAGE = "Internal server error";
205
+ var DIALECT_LEAK_PHRASINGS = [
206
+ // Postgres 42P01 / 42703 (and, as a superstring, the `… of relation "…"`
207
+ // sub-object family: 42704 and friends). The quotes are required because
208
+ // Postgres always emits them here.
209
+ /\b(?:relation|column)\s+["'`][^"'`]+["'`]\s+does not exist/i,
210
+ // Postgres 42501. Restricted to physical object kinds: `schema`, `view`,
211
+ // `function` and `column` are all ObjectStack AUTHORING vocabulary, so a
212
+ // product message could legitimately use them and a miss is the cheap
213
+ // direction (the outcome is already a 5xx).
214
+ /\bpermission denied for (?:table|relation|sequence|database)\b/i,
215
+ // SQLite/libsql, message-only form. The `sqlite_` limb below catches these
216
+ // only when the driver prefixed its code; `better-sqlite3` and libsql both
217
+ // raise them bare, which is the shape measured across this repo.
218
+ /\bno such (?:table|column):/i
219
+ ];
199
220
  function looksLikeInternalErrorLeak(message) {
200
221
  if (!message) return false;
201
222
  const lower = String(message).toLowerCase();
202
- 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");
223
+ 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));
203
224
  }
204
225
  function declaresServerFault(err) {
205
226
  if (typeof err !== "object" || err === null) return false;
@@ -284,6 +305,62 @@ function sendError(res, status, code, message, extra) {
284
305
  res.status(status).json({ success: false, error: { code, message, ...extra } });
285
306
  }
286
307
 
308
+ // src/thrown-http-error.ts
309
+ var import_api2 = require("@objectstack/spec/api");
310
+
311
+ // src/validation-failure.ts
312
+ var import_api = require("@objectstack/spec/api");
313
+ var VALIDATION_FAILED_STATUS = 400;
314
+ function validationFailureDetails(err) {
315
+ if (!err) return void 0;
316
+ if (err.code !== "VALIDATION_FAILED" && err.name !== "ValidationError") return void 0;
317
+ return {
318
+ code: "VALIDATION_FAILED",
319
+ fields: Array.isArray(err.fields) ? err.fields : []
320
+ };
321
+ }
322
+ function validationFailure(message, fields) {
323
+ const err = new Error(message);
324
+ err.name = "ValidationError";
325
+ err.code = "VALIDATION_FAILED";
326
+ err.fields = fields;
327
+ return err;
328
+ }
329
+ function fieldsFromZodIssues(issues, ...input) {
330
+ return (0, import_api.zodIssuesToFields)(issues, ...input).map(
331
+ (entry) => entry.field === "" ? { ...entry, field: "(body)" } : entry
332
+ );
333
+ }
334
+
335
+ // src/thrown-http-error.ts
336
+ function resolveThrownHttpError(error, fallbackStatus = 500) {
337
+ const e = error;
338
+ const validation = validationFailureDetails(e);
339
+ const declaredStatus = typeof e?.status === "number" ? e.status : typeof e?.statusCode === "number" ? e.statusCode : validation ? VALIDATION_FAILED_STATUS : void 0;
340
+ const status = declaredStatus ?? fallbackStatus;
341
+ const spelled = typeof e?.code === "string" && e.code !== "" ? e.code : void 0;
342
+ const registered = spelled !== void 0 && import_api2.ErrorCode.safeParse(spelled).success ? spelled : void 0;
343
+ const code = validation ? validation.code : registered ?? (0, import_api2.standardErrorCodeForHttpStatus)(status);
344
+ const declaredCode = validation ? validation.code : spelled;
345
+ const issues = Array.isArray(e?.issues) ? e.issues : void 0;
346
+ const details = {
347
+ // A truthy NON-string `code` (a driver errno, say) is context and stays
348
+ // context — promoting it would put a number in the field callers branch on,
349
+ // which is the drift #3842 removed.
350
+ ...!validation && e?.code && typeof e.code !== "string" ? { code: e.code } : {},
351
+ ...issues ? { issues } : {},
352
+ ...validation ? { fields: validation.fields } : {}
353
+ };
354
+ return {
355
+ status,
356
+ ...declaredStatus !== void 0 ? { declaredStatus } : {},
357
+ code,
358
+ ...declaredCode !== void 0 ? { declaredCode } : {},
359
+ message: typeof e?.message === "string" ? e.message : String(error),
360
+ ...Object.keys(details).length > 0 ? { details } : {}
361
+ };
362
+ }
363
+
287
364
  // src/relation-sub-object.ts
288
365
  function matchMissingColumnOfRelation(message) {
289
366
  return MISSING_COLUMN_OF_RELATION.exec(message)?.[1];
@@ -360,6 +437,23 @@ function uniqueViolationColumn(error) {
360
437
  return findUniqueViolationColumn(error, 0);
361
438
  }
362
439
 
440
+ // src/unbacked-conflict-target.ts
441
+ var UNBACKED_CONFLICT_TARGET = {
442
+ 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
443
+ };
444
+ var MAX_CAUSE_DEPTH2 = 4;
445
+ function isUnbackedConflictTargetError(error) {
446
+ return matchesUnbackedConflictTarget(error, 0);
447
+ }
448
+ function matchesUnbackedConflictTarget(error, depth) {
449
+ if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH2) return false;
450
+ if (typeof error === "string") return UNBACKED_CONFLICT_TARGET.message.test(error);
451
+ if (typeof error !== "object") return false;
452
+ const err = error;
453
+ if (typeof err.message === "string" && UNBACKED_CONFLICT_TARGET.message.test(err.message)) return true;
454
+ return matchesUnbackedConflictTarget(err.cause, depth + 1);
455
+ }
456
+
363
457
  // src/unique-scope-install-gate.ts
364
458
  var import_security2 = require("@objectstack/spec/security");
365
459
  var SYS_OBJECT_PREFIXES = ["sys_", "base_"];
@@ -462,6 +556,7 @@ function postureGatesGlobalUniques(posture) {
462
556
  GLOBAL_UNIQUE_CONFIRMATION_REQUIRED,
463
557
  GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION,
464
558
  INTERNAL_ERROR_MESSAGE,
559
+ VALIDATION_FAILED_STATUS,
465
560
  _resetEnvDeprecationWarnings,
466
561
  buildGlobalUniqueStopMessage,
467
562
  collectConfiguredLocales,
@@ -471,11 +566,13 @@ function postureGatesGlobalUniques(posture) {
471
566
  describeGlobalUniqueFinding,
472
567
  emitDegradedBootBanner,
473
568
  fieldUniqueIsGlobal,
569
+ fieldsFromZodIssues,
474
570
  globalUniqueFindingId,
475
571
  isMcpServerEnabled,
476
572
  isModuleNotFoundError,
477
573
  isPlatformOwnedObject,
478
574
  isRelationSubObjectPhrase,
575
+ isUnbackedConflictTargetError,
479
576
  isUniqueViolationError,
480
577
  keysetWalk,
481
578
  looksLikeInternalErrorLeak,
@@ -492,10 +589,13 @@ function postureGatesGlobalUniques(posture) {
492
589
  resolveSandboxTimeoutMs,
493
590
  resolveSearchPinyinEnabled,
494
591
  resolveTenancyPosture,
592
+ resolveThrownHttpError,
495
593
  sendError,
496
594
  sendOk,
497
595
  stampSearchPinyinEnabled,
498
596
  unconfirmedGlobalUniques,
499
- uniqueViolationColumn
597
+ uniqueViolationColumn,
598
+ validationFailure,
599
+ validationFailureDetails
500
600
  });
501
601
  //# sourceMappingURL=index.js.map