@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/CHANGELOG.md +2293 -0
- package/dist/index.d.mts +429 -6
- package/dist/index.d.ts +429 -6
- package/dist/index.js +187 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +176 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
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,12 +33,17 @@ __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,
|
|
41
|
+
isRelationSubObjectPhrase: () => isRelationSubObjectPhrase,
|
|
42
|
+
isUnbackedConflictTargetError: () => isUnbackedConflictTargetError,
|
|
43
|
+
isUniqueViolationError: () => isUniqueViolationError,
|
|
39
44
|
keysetWalk: () => keysetWalk,
|
|
40
45
|
looksLikeInternalErrorLeak: () => looksLikeInternalErrorLeak,
|
|
46
|
+
matchMissingColumnOfRelation: () => matchMissingColumnOfRelation,
|
|
41
47
|
postureGatesGlobalUniques: () => postureGatesGlobalUniques,
|
|
42
48
|
readEnvWithDeprecation: () => readEnvWithDeprecation,
|
|
43
49
|
recordGlobalUniqueAttestation: () => recordGlobalUniqueAttestation,
|
|
@@ -50,10 +56,14 @@ __export(index_exports, {
|
|
|
50
56
|
resolveSandboxTimeoutMs: () => resolveSandboxTimeoutMs,
|
|
51
57
|
resolveSearchPinyinEnabled: () => resolveSearchPinyinEnabled,
|
|
52
58
|
resolveTenancyPosture: () => resolveTenancyPosture,
|
|
59
|
+
resolveThrownHttpError: () => resolveThrownHttpError,
|
|
53
60
|
sendError: () => sendError,
|
|
54
61
|
sendOk: () => sendOk,
|
|
55
62
|
stampSearchPinyinEnabled: () => stampSearchPinyinEnabled,
|
|
56
|
-
unconfirmedGlobalUniques: () => unconfirmedGlobalUniques
|
|
63
|
+
unconfirmedGlobalUniques: () => unconfirmedGlobalUniques,
|
|
64
|
+
uniqueViolationColumn: () => uniqueViolationColumn,
|
|
65
|
+
validationFailure: () => validationFailure,
|
|
66
|
+
validationFailureDetails: () => validationFailureDetails
|
|
57
67
|
});
|
|
58
68
|
module.exports = __toCommonJS(index_exports);
|
|
59
69
|
|
|
@@ -192,10 +202,25 @@ function _resetEnvDeprecationWarnings() {
|
|
|
192
202
|
|
|
193
203
|
// src/error-leak.ts
|
|
194
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
|
+
];
|
|
195
220
|
function looksLikeInternalErrorLeak(message) {
|
|
196
221
|
if (!message) return false;
|
|
197
222
|
const lower = String(message).toLowerCase();
|
|
198
|
-
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));
|
|
199
224
|
}
|
|
200
225
|
function declaresServerFault(err) {
|
|
201
226
|
if (typeof err !== "object" || err === null) return false;
|
|
@@ -280,6 +305,155 @@ function sendError(res, status, code, message, extra) {
|
|
|
280
305
|
res.status(status).json({ success: false, error: { code, message, ...extra } });
|
|
281
306
|
}
|
|
282
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
|
+
|
|
364
|
+
// src/relation-sub-object.ts
|
|
365
|
+
function matchMissingColumnOfRelation(message) {
|
|
366
|
+
return MISSING_COLUMN_OF_RELATION.exec(message)?.[1];
|
|
367
|
+
}
|
|
368
|
+
function isRelationSubObjectPhrase(message) {
|
|
369
|
+
return RELATION_SUB_OBJECT.test(message);
|
|
370
|
+
}
|
|
371
|
+
var MISSING_COLUMN_OF_RELATION = /column\s+["'`]([a-z0-9_]+)["'`]\s+of relation\s+\S+\s+does not exist/i;
|
|
372
|
+
var RELATION_SUB_OBJECT = /["'`][^"'`]+["'`]\s+of relation\s/i;
|
|
373
|
+
|
|
374
|
+
// src/unique-violation.ts
|
|
375
|
+
var UNIQUE_VIOLATION = {
|
|
376
|
+
codes: /* @__PURE__ */ new Set(["23505", "ER_DUP_ENTRY", "SQLITE_CONSTRAINT_UNIQUE"]),
|
|
377
|
+
errnos: /* @__PURE__ */ new Set([1062]),
|
|
378
|
+
message: /unique constraint|unique violation|duplicate key|duplicate entry/i
|
|
379
|
+
};
|
|
380
|
+
var MAX_CAUSE_DEPTH = 4;
|
|
381
|
+
function isUniqueViolationError(error) {
|
|
382
|
+
return matchesUniqueViolation(error, 0);
|
|
383
|
+
}
|
|
384
|
+
function matchesUniqueViolation(error, depth) {
|
|
385
|
+
if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH) return false;
|
|
386
|
+
if (typeof error === "string") return UNIQUE_VIOLATION.message.test(error);
|
|
387
|
+
if (typeof error !== "object") return false;
|
|
388
|
+
const err = error;
|
|
389
|
+
if (typeof err.code === "string" && UNIQUE_VIOLATION.codes.has(err.code)) return true;
|
|
390
|
+
if (typeof err.code === "number" && UNIQUE_VIOLATION.errnos.has(err.code)) return true;
|
|
391
|
+
if (typeof err.errno === "number" && UNIQUE_VIOLATION.errnos.has(err.errno)) return true;
|
|
392
|
+
if (typeof err.message === "string" && UNIQUE_VIOLATION.message.test(err.message)) return true;
|
|
393
|
+
return matchesUniqueViolation(err.cause, depth + 1);
|
|
394
|
+
}
|
|
395
|
+
var SQLITE_TARGETS = /unique constraint failed:\s*([^\n]*)/i;
|
|
396
|
+
var POSTGRES_DETAIL_TARGETS = /\bkey \(([^)]+)\)=\(/i;
|
|
397
|
+
var SQLITE_INDEX_FORM = /^index\b/i;
|
|
398
|
+
var PLAIN_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_$]*$/;
|
|
399
|
+
function bareIdentifier(raw) {
|
|
400
|
+
const stripped = raw.trim().replace(/[`"'[\]]/g, "");
|
|
401
|
+
const dot = stripped.lastIndexOf(".");
|
|
402
|
+
return dot >= 0 ? stripped.slice(dot + 1) : stripped;
|
|
403
|
+
}
|
|
404
|
+
function soleColumn(targets) {
|
|
405
|
+
const names = targets.split(",").map(bareIdentifier);
|
|
406
|
+
if (names.length !== 1) return void 0;
|
|
407
|
+
const [name] = names;
|
|
408
|
+
return PLAIN_IDENTIFIER.test(name) ? name : void 0;
|
|
409
|
+
}
|
|
410
|
+
function columnFromText(text) {
|
|
411
|
+
const sqlite = SQLITE_TARGETS.exec(text);
|
|
412
|
+
if (sqlite) {
|
|
413
|
+
const targets = sqlite[1].trim();
|
|
414
|
+
return SQLITE_INDEX_FORM.test(targets) ? void 0 : soleColumn(targets);
|
|
415
|
+
}
|
|
416
|
+
const postgres = POSTGRES_DETAIL_TARGETS.exec(text);
|
|
417
|
+
if (postgres) return soleColumn(postgres[1]);
|
|
418
|
+
return void 0;
|
|
419
|
+
}
|
|
420
|
+
function findUniqueViolationColumn(error, depth) {
|
|
421
|
+
if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH) return void 0;
|
|
422
|
+
if (typeof error === "string") return columnFromText(error);
|
|
423
|
+
if (typeof error !== "object") return void 0;
|
|
424
|
+
const err = error;
|
|
425
|
+
if (typeof err.message === "string") {
|
|
426
|
+
const fromMessage = columnFromText(err.message);
|
|
427
|
+
if (fromMessage !== void 0) return fromMessage;
|
|
428
|
+
}
|
|
429
|
+
if (typeof err.detail === "string") {
|
|
430
|
+
const fromDetail = columnFromText(err.detail);
|
|
431
|
+
if (fromDetail !== void 0) return fromDetail;
|
|
432
|
+
}
|
|
433
|
+
return findUniqueViolationColumn(err.cause, depth + 1);
|
|
434
|
+
}
|
|
435
|
+
function uniqueViolationColumn(error) {
|
|
436
|
+
if (!isUniqueViolationError(error)) return void 0;
|
|
437
|
+
return findUniqueViolationColumn(error, 0);
|
|
438
|
+
}
|
|
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
|
+
|
|
283
457
|
// src/unique-scope-install-gate.ts
|
|
284
458
|
var import_security2 = require("@objectstack/spec/security");
|
|
285
459
|
var SYS_OBJECT_PREFIXES = ["sys_", "base_"];
|
|
@@ -382,6 +556,7 @@ function postureGatesGlobalUniques(posture) {
|
|
|
382
556
|
GLOBAL_UNIQUE_CONFIRMATION_REQUIRED,
|
|
383
557
|
GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION,
|
|
384
558
|
INTERNAL_ERROR_MESSAGE,
|
|
559
|
+
VALIDATION_FAILED_STATUS,
|
|
385
560
|
_resetEnvDeprecationWarnings,
|
|
386
561
|
buildGlobalUniqueStopMessage,
|
|
387
562
|
collectConfiguredLocales,
|
|
@@ -391,12 +566,17 @@ function postureGatesGlobalUniques(posture) {
|
|
|
391
566
|
describeGlobalUniqueFinding,
|
|
392
567
|
emitDegradedBootBanner,
|
|
393
568
|
fieldUniqueIsGlobal,
|
|
569
|
+
fieldsFromZodIssues,
|
|
394
570
|
globalUniqueFindingId,
|
|
395
571
|
isMcpServerEnabled,
|
|
396
572
|
isModuleNotFoundError,
|
|
397
573
|
isPlatformOwnedObject,
|
|
574
|
+
isRelationSubObjectPhrase,
|
|
575
|
+
isUnbackedConflictTargetError,
|
|
576
|
+
isUniqueViolationError,
|
|
398
577
|
keysetWalk,
|
|
399
578
|
looksLikeInternalErrorLeak,
|
|
579
|
+
matchMissingColumnOfRelation,
|
|
400
580
|
postureGatesGlobalUniques,
|
|
401
581
|
readEnvWithDeprecation,
|
|
402
582
|
recordGlobalUniqueAttestation,
|
|
@@ -409,9 +589,13 @@ function postureGatesGlobalUniques(posture) {
|
|
|
409
589
|
resolveSandboxTimeoutMs,
|
|
410
590
|
resolveSearchPinyinEnabled,
|
|
411
591
|
resolveTenancyPosture,
|
|
592
|
+
resolveThrownHttpError,
|
|
412
593
|
sendError,
|
|
413
594
|
sendOk,
|
|
414
595
|
stampSearchPinyinEnabled,
|
|
415
|
-
unconfirmedGlobalUniques
|
|
596
|
+
unconfirmedGlobalUniques,
|
|
597
|
+
uniqueViolationColumn,
|
|
598
|
+
validationFailure,
|
|
599
|
+
validationFailureDetails
|
|
416
600
|
});
|
|
417
601
|
//# sourceMappingURL=index.js.map
|