@objectstack/types 17.0.0-rc.6 → 17.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/CHANGELOG.md +2340 -0
- package/dist/index.d.mts +318 -6
- package/dist/index.d.ts +318 -6
- package/dist/index.js +139 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +130 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -136,10 +136,47 @@ 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
|
+
// [#8739] MySQL/MariaDB ER_NO_SUCH_TABLE (1146): `Table 'app.t' doesn't
|
|
154
|
+
// exist`. Its own template, not a spelling of the Postgres one — MySQL
|
|
155
|
+
// contracts the verb and quotes `db.table` as a single identifier — so the
|
|
156
|
+
// `relation|column … does not exist` limb above cannot reach it. The quotes
|
|
157
|
+
// are required for the same reason they are there: the driver always emits
|
|
158
|
+
// them and prose about a table usually does not.
|
|
159
|
+
/\btable\s+["'`][^"'`]+["'`]\s+doesn't exist/i,
|
|
160
|
+
// [#8739] MySQL/MariaDB ER_BAD_FIELD_ERROR (1054): `Unknown column 'c' in
|
|
161
|
+
// 'field list'`. BOTH quoted parts are required. The second is MySQL's clause
|
|
162
|
+
// name — `field list`, `where clause`, `order clause`, `on clause` — and it
|
|
163
|
+
// is the half that makes this the driver's template rather than a sentence
|
|
164
|
+
// that merely calls a column unknown, which an import or mapping feature has
|
|
165
|
+
// every right to say.
|
|
166
|
+
/\bunknown column\s+["'`][^"'`]+["'`]\s+in\s+["'`][^"'`]+["'`]/i,
|
|
167
|
+
// [#8739] MySQL/MariaDB ER_DUP_ENTRY (1062): `Duplicate entry
|
|
168
|
+
// 'acme@example.com' for key 'crm_account.email'`. `for key` + a quoted index
|
|
169
|
+
// is the anchor; the VALUE half is matched loosely and lazily because it is
|
|
170
|
+
// the caller's own text and MySQL does not escape a quote inside it
|
|
171
|
+
// (`Duplicate entry 'O'Brien' for key 'i'` is a real shape). A bare
|
|
172
|
+
// `duplicate entry` with no `for key '…'` tail is not this template and is
|
|
173
|
+
// left alone.
|
|
174
|
+
/\bduplicate entry\s+["'`].*?["'`]\s+for key\s+["'`][^"'`]+["'`]/i
|
|
175
|
+
];
|
|
139
176
|
function looksLikeInternalErrorLeak(message) {
|
|
140
177
|
if (!message) return false;
|
|
141
178
|
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");
|
|
179
|
+
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
180
|
}
|
|
144
181
|
function declaresServerFault(err) {
|
|
145
182
|
if (typeof err !== "object" || err === null) return false;
|
|
@@ -224,6 +261,71 @@ function sendError(res, status, code, message, extra) {
|
|
|
224
261
|
res.status(status).json({ success: false, error: { code, message, ...extra } });
|
|
225
262
|
}
|
|
226
263
|
|
|
264
|
+
// src/thrown-http-error.ts
|
|
265
|
+
import { ErrorCode, standardErrorCodeForHttpStatus } from "@objectstack/spec/api";
|
|
266
|
+
|
|
267
|
+
// src/validation-failure.ts
|
|
268
|
+
import { zodIssuesToFields } from "@objectstack/spec/api";
|
|
269
|
+
var VALIDATION_FAILED_STATUS = 400;
|
|
270
|
+
function validationFailureDetails(err) {
|
|
271
|
+
if (!err) return void 0;
|
|
272
|
+
if (err.code !== "VALIDATION_FAILED" && err.name !== "ValidationError") return void 0;
|
|
273
|
+
return {
|
|
274
|
+
code: "VALIDATION_FAILED",
|
|
275
|
+
fields: Array.isArray(err.fields) ? err.fields : []
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function validationFailure(message, fields) {
|
|
279
|
+
const err = new Error(message);
|
|
280
|
+
err.name = "ValidationError";
|
|
281
|
+
err.code = "VALIDATION_FAILED";
|
|
282
|
+
err.fields = fields;
|
|
283
|
+
return err;
|
|
284
|
+
}
|
|
285
|
+
function fieldsFromZodIssues(issues, ...input) {
|
|
286
|
+
return zodIssuesToFields(issues, ...input).map(
|
|
287
|
+
(entry) => entry.field === "" ? { ...entry, field: "(body)" } : entry
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/thrown-http-error.ts
|
|
292
|
+
function resolveThrownHttpError(error, fallbackStatus = 500) {
|
|
293
|
+
const e = error;
|
|
294
|
+
const validation = validationFailureDetails(e);
|
|
295
|
+
const declaredStatus = typeof e?.status === "number" ? e.status : typeof e?.statusCode === "number" ? e.statusCode : validation ? VALIDATION_FAILED_STATUS : void 0;
|
|
296
|
+
const status = declaredStatus ?? fallbackStatus;
|
|
297
|
+
const spelled = typeof e?.code === "string" && e.code !== "" ? e.code : void 0;
|
|
298
|
+
const registered = spelled !== void 0 && ErrorCode.safeParse(spelled).success ? spelled : void 0;
|
|
299
|
+
const code = validation ? validation.code : registered ?? standardErrorCodeForHttpStatus(status);
|
|
300
|
+
const declaredCode = validation ? validation.code : spelled;
|
|
301
|
+
const issues = Array.isArray(e?.issues) ? e.issues : void 0;
|
|
302
|
+
const details = {
|
|
303
|
+
// A truthy NON-string `code` (a driver errno, say) is context and stays
|
|
304
|
+
// context — promoting it would put a number in the field callers branch on,
|
|
305
|
+
// which is the drift #3842 removed.
|
|
306
|
+
...!validation && e?.code && typeof e.code !== "string" ? { code: e.code } : {},
|
|
307
|
+
...issues ? { issues } : {},
|
|
308
|
+
...validation ? { fields: validation.fields } : {}
|
|
309
|
+
};
|
|
310
|
+
const userMessage = declaredUserMessage(error);
|
|
311
|
+
return {
|
|
312
|
+
status,
|
|
313
|
+
...declaredStatus !== void 0 ? { declaredStatus } : {},
|
|
314
|
+
code,
|
|
315
|
+
...declaredCode !== void 0 ? { declaredCode } : {},
|
|
316
|
+
message: typeof e?.message === "string" ? e.message : String(error),
|
|
317
|
+
...userMessage !== void 0 ? { userMessage } : {},
|
|
318
|
+
...Object.keys(details).length > 0 ? { details } : {}
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function declaredUserMessage(error) {
|
|
322
|
+
const declared = error?.userMessage;
|
|
323
|
+
return typeof declared === "string" && declared.trim().length > 0 ? declared : void 0;
|
|
324
|
+
}
|
|
325
|
+
function demotedDeclaredCode(thrown) {
|
|
326
|
+
return thrown.declaredCode !== void 0 && thrown.declaredCode !== thrown.code ? thrown.declaredCode : void 0;
|
|
327
|
+
}
|
|
328
|
+
|
|
227
329
|
// src/relation-sub-object.ts
|
|
228
330
|
function matchMissingColumnOfRelation(message) {
|
|
229
331
|
return MISSING_COLUMN_OF_RELATION.exec(message)?.[1];
|
|
@@ -238,7 +340,7 @@ var RELATION_SUB_OBJECT = /["'`][^"'`]+["'`]\s+of relation\s/i;
|
|
|
238
340
|
var UNIQUE_VIOLATION = {
|
|
239
341
|
codes: /* @__PURE__ */ new Set(["23505", "ER_DUP_ENTRY", "SQLITE_CONSTRAINT_UNIQUE"]),
|
|
240
342
|
errnos: /* @__PURE__ */ new Set([1062]),
|
|
241
|
-
message: /unique constraint|unique violation|duplicate key|duplicate entry/i
|
|
343
|
+
message: /unique constraint failed|violates unique constraint|unique violation|duplicate key|duplicate entry/i
|
|
242
344
|
};
|
|
243
345
|
var MAX_CAUSE_DEPTH = 4;
|
|
244
346
|
function isUniqueViolationError(error) {
|
|
@@ -300,6 +402,23 @@ function uniqueViolationColumn(error) {
|
|
|
300
402
|
return findUniqueViolationColumn(error, 0);
|
|
301
403
|
}
|
|
302
404
|
|
|
405
|
+
// src/unbacked-conflict-target.ts
|
|
406
|
+
var UNBACKED_CONFLICT_TARGET = {
|
|
407
|
+
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
|
|
408
|
+
};
|
|
409
|
+
var MAX_CAUSE_DEPTH2 = 4;
|
|
410
|
+
function isUnbackedConflictTargetError(error) {
|
|
411
|
+
return matchesUnbackedConflictTarget(error, 0);
|
|
412
|
+
}
|
|
413
|
+
function matchesUnbackedConflictTarget(error, depth) {
|
|
414
|
+
if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH2) return false;
|
|
415
|
+
if (typeof error === "string") return UNBACKED_CONFLICT_TARGET.message.test(error);
|
|
416
|
+
if (typeof error !== "object") return false;
|
|
417
|
+
const err = error;
|
|
418
|
+
if (typeof err.message === "string" && UNBACKED_CONFLICT_TARGET.message.test(err.message)) return true;
|
|
419
|
+
return matchesUnbackedConflictTarget(err.cause, depth + 1);
|
|
420
|
+
}
|
|
421
|
+
|
|
303
422
|
// src/unique-scope-install-gate.ts
|
|
304
423
|
import { normalizeTenancyPosture as normalizeTenancyPosture2 } from "@objectstack/spec/security";
|
|
305
424
|
var SYS_OBJECT_PREFIXES = ["sys_", "base_"];
|
|
@@ -401,20 +520,25 @@ export {
|
|
|
401
520
|
GLOBAL_UNIQUE_CONFIRMATION_REQUIRED,
|
|
402
521
|
GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION,
|
|
403
522
|
INTERNAL_ERROR_MESSAGE,
|
|
523
|
+
VALIDATION_FAILED_STATUS,
|
|
404
524
|
_resetEnvDeprecationWarnings,
|
|
405
525
|
buildGlobalUniqueStopMessage,
|
|
406
526
|
collectConfiguredLocales,
|
|
407
527
|
collectGlobalUniques,
|
|
408
528
|
declaredIndexUniqueIsGlobal,
|
|
529
|
+
declaredUserMessage,
|
|
409
530
|
declaresServerFault,
|
|
531
|
+
demotedDeclaredCode,
|
|
410
532
|
describeGlobalUniqueFinding,
|
|
411
533
|
emitDegradedBootBanner,
|
|
412
534
|
fieldUniqueIsGlobal,
|
|
535
|
+
fieldsFromZodIssues,
|
|
413
536
|
globalUniqueFindingId,
|
|
414
537
|
isMcpServerEnabled,
|
|
415
538
|
isModuleNotFoundError,
|
|
416
539
|
isPlatformOwnedObject,
|
|
417
540
|
isRelationSubObjectPhrase,
|
|
541
|
+
isUnbackedConflictTargetError,
|
|
418
542
|
isUniqueViolationError,
|
|
419
543
|
keysetWalk,
|
|
420
544
|
looksLikeInternalErrorLeak,
|
|
@@ -431,10 +555,13 @@ export {
|
|
|
431
555
|
resolveSandboxTimeoutMs,
|
|
432
556
|
resolveSearchPinyinEnabled,
|
|
433
557
|
resolveTenancyPosture,
|
|
558
|
+
resolveThrownHttpError,
|
|
434
559
|
sendError,
|
|
435
560
|
sendOk,
|
|
436
561
|
stampSearchPinyinEnabled,
|
|
437
562
|
unconfirmedGlobalUniques,
|
|
438
|
-
uniqueViolationColumn
|
|
563
|
+
uniqueViolationColumn,
|
|
564
|
+
validationFailure,
|
|
565
|
+
validationFailureDetails
|
|
439
566
|
};
|
|
440
567
|
//# sourceMappingURL=index.mjs.map
|