@objectstack/types 17.0.0-rc.5 → 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,155 @@ 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
+
298
+ // src/relation-sub-object.ts
299
+ function matchMissingColumnOfRelation(message) {
300
+ return MISSING_COLUMN_OF_RELATION.exec(message)?.[1];
301
+ }
302
+ function isRelationSubObjectPhrase(message) {
303
+ return RELATION_SUB_OBJECT.test(message);
304
+ }
305
+ var MISSING_COLUMN_OF_RELATION = /column\s+["'`]([a-z0-9_]+)["'`]\s+of relation\s+\S+\s+does not exist/i;
306
+ var RELATION_SUB_OBJECT = /["'`][^"'`]+["'`]\s+of relation\s/i;
307
+
308
+ // src/unique-violation.ts
309
+ var UNIQUE_VIOLATION = {
310
+ codes: /* @__PURE__ */ new Set(["23505", "ER_DUP_ENTRY", "SQLITE_CONSTRAINT_UNIQUE"]),
311
+ errnos: /* @__PURE__ */ new Set([1062]),
312
+ message: /unique constraint|unique violation|duplicate key|duplicate entry/i
313
+ };
314
+ var MAX_CAUSE_DEPTH = 4;
315
+ function isUniqueViolationError(error) {
316
+ return matchesUniqueViolation(error, 0);
317
+ }
318
+ function matchesUniqueViolation(error, depth) {
319
+ if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH) return false;
320
+ if (typeof error === "string") return UNIQUE_VIOLATION.message.test(error);
321
+ if (typeof error !== "object") return false;
322
+ const err = error;
323
+ if (typeof err.code === "string" && UNIQUE_VIOLATION.codes.has(err.code)) return true;
324
+ if (typeof err.code === "number" && UNIQUE_VIOLATION.errnos.has(err.code)) return true;
325
+ if (typeof err.errno === "number" && UNIQUE_VIOLATION.errnos.has(err.errno)) return true;
326
+ if (typeof err.message === "string" && UNIQUE_VIOLATION.message.test(err.message)) return true;
327
+ return matchesUniqueViolation(err.cause, depth + 1);
328
+ }
329
+ var SQLITE_TARGETS = /unique constraint failed:\s*([^\n]*)/i;
330
+ var POSTGRES_DETAIL_TARGETS = /\bkey \(([^)]+)\)=\(/i;
331
+ var SQLITE_INDEX_FORM = /^index\b/i;
332
+ var PLAIN_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_$]*$/;
333
+ function bareIdentifier(raw) {
334
+ const stripped = raw.trim().replace(/[`"'[\]]/g, "");
335
+ const dot = stripped.lastIndexOf(".");
336
+ return dot >= 0 ? stripped.slice(dot + 1) : stripped;
337
+ }
338
+ function soleColumn(targets) {
339
+ const names = targets.split(",").map(bareIdentifier);
340
+ if (names.length !== 1) return void 0;
341
+ const [name] = names;
342
+ return PLAIN_IDENTIFIER.test(name) ? name : void 0;
343
+ }
344
+ function columnFromText(text) {
345
+ const sqlite = SQLITE_TARGETS.exec(text);
346
+ if (sqlite) {
347
+ const targets = sqlite[1].trim();
348
+ return SQLITE_INDEX_FORM.test(targets) ? void 0 : soleColumn(targets);
349
+ }
350
+ const postgres = POSTGRES_DETAIL_TARGETS.exec(text);
351
+ if (postgres) return soleColumn(postgres[1]);
352
+ return void 0;
353
+ }
354
+ function findUniqueViolationColumn(error, depth) {
355
+ if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH) return void 0;
356
+ if (typeof error === "string") return columnFromText(error);
357
+ if (typeof error !== "object") return void 0;
358
+ const err = error;
359
+ if (typeof err.message === "string") {
360
+ const fromMessage = columnFromText(err.message);
361
+ if (fromMessage !== void 0) return fromMessage;
362
+ }
363
+ if (typeof err.detail === "string") {
364
+ const fromDetail = columnFromText(err.detail);
365
+ if (fromDetail !== void 0) return fromDetail;
366
+ }
367
+ return findUniqueViolationColumn(err.cause, depth + 1);
368
+ }
369
+ function uniqueViolationColumn(error) {
370
+ if (!isUniqueViolationError(error)) return void 0;
371
+ return findUniqueViolationColumn(error, 0);
372
+ }
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
+
227
391
  // src/unique-scope-install-gate.ts
228
392
  import { normalizeTenancyPosture as normalizeTenancyPosture2 } from "@objectstack/spec/security";
229
393
  var SYS_OBJECT_PREFIXES = ["sys_", "base_"];
@@ -325,6 +489,7 @@ export {
325
489
  GLOBAL_UNIQUE_CONFIRMATION_REQUIRED,
326
490
  GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION,
327
491
  INTERNAL_ERROR_MESSAGE,
492
+ VALIDATION_FAILED_STATUS,
328
493
  _resetEnvDeprecationWarnings,
329
494
  buildGlobalUniqueStopMessage,
330
495
  collectConfiguredLocales,
@@ -334,12 +499,17 @@ export {
334
499
  describeGlobalUniqueFinding,
335
500
  emitDegradedBootBanner,
336
501
  fieldUniqueIsGlobal,
502
+ fieldsFromZodIssues,
337
503
  globalUniqueFindingId,
338
504
  isMcpServerEnabled,
339
505
  isModuleNotFoundError,
340
506
  isPlatformOwnedObject,
507
+ isRelationSubObjectPhrase,
508
+ isUnbackedConflictTargetError,
509
+ isUniqueViolationError,
341
510
  keysetWalk,
342
511
  looksLikeInternalErrorLeak,
512
+ matchMissingColumnOfRelation,
343
513
  postureGatesGlobalUniques,
344
514
  readEnvWithDeprecation,
345
515
  recordGlobalUniqueAttestation,
@@ -352,9 +522,13 @@ export {
352
522
  resolveSandboxTimeoutMs,
353
523
  resolveSearchPinyinEnabled,
354
524
  resolveTenancyPosture,
525
+ resolveThrownHttpError,
355
526
  sendError,
356
527
  sendOk,
357
528
  stampSearchPinyinEnabled,
358
- unconfirmedGlobalUniques
529
+ unconfirmedGlobalUniques,
530
+ uniqueViolationColumn,
531
+ validationFailure,
532
+ validationFailureDetails
359
533
  };
360
534
  //# sourceMappingURL=index.mjs.map