@objectstack/types 17.0.0-rc.5 → 17.0.0-rc.6
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 +302 -0
- package/dist/index.d.mts +192 -1
- package/dist/index.d.ts +192 -1
- package/dist/index.js +86 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +81 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -680,6 +680,197 @@ declare function sendOk(res: EnvelopeResponse, data: unknown, status?: number):
|
|
|
680
680
|
*/
|
|
681
681
|
declare function sendError(res: EnvelopeResponse, status: number, code: ErrorCode, message: string, extra?: Pick<ApiError, 'category' | 'httpStatus' | 'details' | 'requestId'>): void;
|
|
682
682
|
|
|
683
|
+
/**
|
|
684
|
+
* The one home for Postgres' `«sub-object» "x" of relation "y" …` phrasing
|
|
685
|
+
* (#6615).
|
|
686
|
+
*
|
|
687
|
+
* ## The superstring hole, stated once
|
|
688
|
+
*
|
|
689
|
+
* Postgres phrases a failure about something *inside* a relation by naming the
|
|
690
|
+
* relation too:
|
|
691
|
+
*
|
|
692
|
+
* ```
|
|
693
|
+
* column "label" of relation "sys_team" does not exist (42703)
|
|
694
|
+
* constraint "uq_sys_team_name" of relation "sys_team" does not exist (42704)
|
|
695
|
+
* column "environment_id" of relation "sys_metadata" already exists (42701)
|
|
696
|
+
* ```
|
|
697
|
+
*
|
|
698
|
+
* Every one of those **contains a complete, legal missing-TABLE phrase** —
|
|
699
|
+
* `relation "sys_team" does not exist` — as a substring, while meaning the
|
|
700
|
+
* opposite: the relation is right there, which is precisely why it could be
|
|
701
|
+
* named. No amount of tightening a "does this say a relation is missing?"
|
|
702
|
+
* regex can remove that match, because the phrase really is in there. The only
|
|
703
|
+
* repair is to ask the more specific question FIRST. That makes the ORDER the
|
|
704
|
+
* fix, not the pattern — and it is why three packages each grew their own copy
|
|
705
|
+
* of this phrase (#5352, #6035/PR #6346, #6347/PR #6613) before it was given a
|
|
706
|
+
* home.
|
|
707
|
+
*
|
|
708
|
+
* ## Two widths, on purpose — never collapse them
|
|
709
|
+
*
|
|
710
|
+
* The three consumers do not want the same regex, and the difference is not
|
|
711
|
+
* sloppiness: it is **which direction of error is safe** at each site.
|
|
712
|
+
*
|
|
713
|
+
* | consumer | asks | uses | a MISS costs |
|
|
714
|
+
* |:---|:---|:---|:---|
|
|
715
|
+
* | `@objectstack/rest` `mapDataError` (#5352) | which column? | {@link matchMissingColumnOfRelation} | a vaguer message (`404` instead of `400 INVALID_FIELD`) |
|
|
716
|
+
* | `@objectstack/service-analytics` `isMissingSourceError` / `missingSourceRelation` (#6035) | is this a missing COLUMN, so keep it hard? | {@link matchMissingColumnOfRelation} | a mistyped column degrades to a confident empty chart |
|
|
717
|
+
* | `@objectstack/metadata` `MISSING_TABLE.excludes` (#6347) | is this about a sub-object, so not a missing table? | {@link isRelationSubObjectPhrase} | a corruption verdict returns (`event_seq` restarts at 1) |
|
|
718
|
+
*
|
|
719
|
+
* The first two **extract**, so they must be strict: over-matching there would
|
|
720
|
+
* turn a genuinely missing table into a hard failure and regress #5033's
|
|
721
|
+
* deliberate leniency, while under-matching merely keeps today's verdict. The
|
|
722
|
+
* third **excludes**, so it is deliberately wider — any sub-object, any quoted
|
|
723
|
+
* identifier, any verdict — because over-matching there only ever converts a
|
|
724
|
+
* benign verdict into a loud one, and a miss restores data corruption.
|
|
725
|
+
*
|
|
726
|
+
* Collapsing the two into one regex would therefore be wrong for one caller
|
|
727
|
+
* whichever width won. They are two exports for that reason, and the reason is
|
|
728
|
+
* load-bearing rather than stylistic.
|
|
729
|
+
*
|
|
730
|
+
* ## Home
|
|
731
|
+
*
|
|
732
|
+
* `@objectstack/types`, following `isUniqueViolationError`'s move
|
|
733
|
+
* (#6250 — four hand-written answers to one question) and
|
|
734
|
+
* `isModuleNotFoundError`'s (framework#3265 — "single shared owner … so the
|
|
735
|
+
* parallel loaders cannot drift apart"). This module deliberately imports
|
|
736
|
+
* nothing.
|
|
737
|
+
*
|
|
738
|
+
* ⚠️ Unlike #6250, adopting this **does** add one dependency edge:
|
|
739
|
+
* `@objectstack/service-analytics` did not depend on `@objectstack/types`
|
|
740
|
+
* before #6615. It is acyclic by construction — `@objectstack/types` depends
|
|
741
|
+
* only on `@objectstack/spec`, which depends on nothing in-repo, so no package
|
|
742
|
+
* except `spec` itself can form a cycle by consuming it — and 25 of the repo's
|
|
743
|
+
* 73 packages (5 of 16 services) already carry the same edge. Recorded here
|
|
744
|
+
* rather than left for a reader to rediscover.
|
|
745
|
+
*/
|
|
746
|
+
/**
|
|
747
|
+
* Postgres' missing-COLUMN template, strictly. Returns the column name, or
|
|
748
|
+
* `undefined` when the message is not that phrase.
|
|
749
|
+
*
|
|
750
|
+
* Anchored to `column "%s" of relation "%s" does not exist` — the exact errmsg
|
|
751
|
+
* template Postgres emits for SQLSTATE 42703 on the write path
|
|
752
|
+
* (`INSERT` / `UPDATE` / `ALTER`). Both quotes are required because Postgres
|
|
753
|
+
* always emits them here, and requiring them is the safe direction of error for
|
|
754
|
+
* the two consumers that call this.
|
|
755
|
+
*
|
|
756
|
+
* Deliberately narrow in two further ways, both preserved verbatim from the
|
|
757
|
+
* open-coded copies this replaces:
|
|
758
|
+
*
|
|
759
|
+
* - the identifier is `[a-z0-9_]+` (case-insensitive), so a quoted identifier
|
|
760
|
+
* carrying a space or punctuation is NOT matched. Postgres can quote such
|
|
761
|
+
* names; the consumers accept the miss because a miss is the cheap direction.
|
|
762
|
+
* - the relation is `\S+` — quoted or bare, unparsed. This function answers
|
|
763
|
+
* "which COLUMN", never "which relation".
|
|
764
|
+
*
|
|
765
|
+
* The read-path phrasing `column "bogus" does not exist` is a different
|
|
766
|
+
* sentence with no relation in it, so it does not match — and it does not need
|
|
767
|
+
* to: it carries no missing-table substring, which is the whole hole this
|
|
768
|
+
* module exists for.
|
|
769
|
+
*/
|
|
770
|
+
declare function matchMissingColumnOfRelation(message: string): string | undefined;
|
|
771
|
+
/**
|
|
772
|
+
* The same quirk, **wider**: does this message talk about any sub-object of a
|
|
773
|
+
* relation, in any verdict?
|
|
774
|
+
*
|
|
775
|
+
* Drops all three of {@link matchMissingColumnOfRelation}'s anchors — the
|
|
776
|
+
* literal `column`, the `[a-z0-9_]+` identifier shape, and the trailing
|
|
777
|
+
* `does not exist` — so it also recognises `constraint "uq_x" of relation "y"
|
|
778
|
+
* does not exist` (42704), `column "x" of relation "y" already exists` (42701),
|
|
779
|
+
* and every other sub-object Postgres phrases this way.
|
|
780
|
+
*
|
|
781
|
+
* For **exclusion** callers only. A `true` here means "the relation is present,
|
|
782
|
+
* so whatever else this error is, it is not a missing table"; it does not mean
|
|
783
|
+
* the error is benign and it names nothing. Using it to extract would be a
|
|
784
|
+
* category error — there is no capture group precisely so that it cannot be.
|
|
785
|
+
*/
|
|
786
|
+
declare function isRelationSubObjectPhrase(message: string): boolean;
|
|
787
|
+
|
|
788
|
+
/**
|
|
789
|
+
* Whether a thrown driver error is a unique/primary-key constraint violation.
|
|
790
|
+
*
|
|
791
|
+
* Reads all three channels in turn — `code`, `errno`, `message` — then one step
|
|
792
|
+
* down the `cause` chain, because pool and query-builder layers re-throw with
|
|
793
|
+
* the original attached. A plain string is judged on the message channel, so a
|
|
794
|
+
* caller that has already unwrapped `err.message` can pass it straight in.
|
|
795
|
+
*
|
|
796
|
+
* **Unrecognised is always `false`.** The default has to be "not a conflict":
|
|
797
|
+
* a false positive relabels an unrelated failure as the client's fault (a 409
|
|
798
|
+
* an SDK will not retry, pointing at a value that is fine), while a false
|
|
799
|
+
* negative costs only the generic envelope that was the status quo.
|
|
800
|
+
*
|
|
801
|
+
* @param error - the thrown value, of any shape.
|
|
802
|
+
*
|
|
803
|
+
* @example
|
|
804
|
+
* ```ts
|
|
805
|
+
* catch (error) {
|
|
806
|
+
* if (isUniqueViolationError(error)) return conflict(); // 409 UNIQUE_VIOLATION
|
|
807
|
+
* throw error;
|
|
808
|
+
* }
|
|
809
|
+
* ```
|
|
810
|
+
*/
|
|
811
|
+
declare function isUniqueViolationError(error: unknown): boolean;
|
|
812
|
+
/**
|
|
813
|
+
* Which column a unique-constraint violation was raised on — or `undefined`
|
|
814
|
+
* when the dialect did not determinably name one (#6544).
|
|
815
|
+
*
|
|
816
|
+
* ## The contract, and why it is this narrow
|
|
817
|
+
*
|
|
818
|
+
* **A value comes back only when the identifier the driver printed is
|
|
819
|
+
* determinably a COLUMN.** When a dialect names an *index* instead — MySQL's
|
|
820
|
+
* `Duplicate entry 'a@b.com' for key 'idx_email_unique'`, Postgres'
|
|
821
|
+
* `violates unique constraint "sys_user_email_key"`, SQLite's
|
|
822
|
+
* `UNIQUE constraint failed: index 'idx_lower_email'` — the answer is
|
|
823
|
+
* `undefined`, never the index name.
|
|
824
|
+
*
|
|
825
|
+
* That is the maintainer's 2026-08-08 ruling on #6544, and the reasoning is the
|
|
826
|
+
* caller's, not this module's: **an index name mistaken for a column is worse
|
|
827
|
+
* than no answer at all.**
|
|
828
|
+
*
|
|
829
|
+
* - `@objectstack/rest`'s import runner renders this into a form field —
|
|
830
|
+
* "A record with this `email` already exists." An index name there points
|
|
831
|
+
* the user at a field that does not exist on the object, so they cannot act
|
|
832
|
+
* on it; `undefined` degrades to generic copy, which is merely less helpful.
|
|
833
|
+
* - #5495's autonumber-retry branch asks a yes/no question of the answer —
|
|
834
|
+
* "is the conflicting column the autonumber field?" — and an index name
|
|
835
|
+
* produces a *wrong retry decision*, not a vaguer one.
|
|
836
|
+
*
|
|
837
|
+
* ⛔ **The accepted cost: MySQL deployments usually get no column.** MySQL's
|
|
838
|
+
* duplicate-entry message names the index and never the column, so there is
|
|
839
|
+
* nothing here to read. That is deliberate. Do not "improve" this by deriving a
|
|
840
|
+
* column from an index name (`idx_email_unique` → `email`, or MySQL 8's
|
|
841
|
+
* `for key 'sys_user.email'` → `email`): index names are free-form, a
|
|
842
|
+
* deployment's may match no column at all, and a plausible-looking wrong field
|
|
843
|
+
* is exactly the failure this export exists to avoid. If MySQL must name
|
|
844
|
+
* columns, the answer is a schema lookup of the index — a different, wider
|
|
845
|
+
* contract — not a guess in this function.
|
|
846
|
+
*
|
|
847
|
+
* A **composite** key is `undefined` for the same reason: `Key (tenant_id,
|
|
848
|
+
* email)=(…)` has no single offending column, and naming the first is the same
|
|
849
|
+
* class of wrong answer.
|
|
850
|
+
*
|
|
851
|
+
* ## What it reads
|
|
852
|
+
*
|
|
853
|
+
* Gated on {@link isUniqueViolationError}, so a NOT NULL or FOREIGN KEY failure
|
|
854
|
+
* can never reach the extraction — SQLite's `NOT NULL constraint failed: t.c`
|
|
855
|
+
* shares its shape with the positive and is refused at the gate, not by the
|
|
856
|
+
* patterns. Then `message`, then `detail` (node-postgres keeps its `DETAIL:`
|
|
857
|
+
* line there), then one step down the `cause` chain, bounded exactly as the
|
|
858
|
+
* predicate's walk is. A bare string is read as a message, so a caller holding
|
|
859
|
+
* only `err.message` can pass it straight in.
|
|
860
|
+
*
|
|
861
|
+
* @param error - the thrown value, of any shape.
|
|
862
|
+
* @returns the conflicting column, or `undefined` when none is determinable.
|
|
863
|
+
*
|
|
864
|
+
* @example
|
|
865
|
+
* ```ts
|
|
866
|
+
* const column = uniqueViolationColumn(error);
|
|
867
|
+
* return column
|
|
868
|
+
* ? `A record with this ${column} already exists.`
|
|
869
|
+
* : 'A record with this value already exists.';
|
|
870
|
+
* ```
|
|
871
|
+
*/
|
|
872
|
+
declare function uniqueViolationColumn(error: unknown): string | undefined;
|
|
873
|
+
|
|
683
874
|
/**
|
|
684
875
|
* [ADR-0120 D5e] The `isolated`-posture install gate for `'global'` uniqueness.
|
|
685
876
|
*
|
|
@@ -904,4 +1095,4 @@ interface RuntimePlugin {
|
|
|
904
1095
|
onStart?: (ctx: RuntimeContext) => void | Promise<void>;
|
|
905
1096
|
}
|
|
906
1097
|
|
|
907
|
-
export { type EnvelopeResponse, GLOBAL_UNIQUE_CONFIRMATION_REQUIRED, GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION, type GlobalUniqueAttestation, type GlobalUniqueFinding, type IKernel, INTERNAL_ERROR_MESSAGE, type KeysetPageQuery, type KeysetWalk, type KeysetWalkOptions, type RuntimeContext, type RuntimePlugin, _resetEnvDeprecationWarnings, buildGlobalUniqueStopMessage, collectConfiguredLocales, collectGlobalUniques, declaredIndexUniqueIsGlobal, declaresServerFault, describeGlobalUniqueFinding, emitDegradedBootBanner, fieldUniqueIsGlobal, globalUniqueFindingId, isMcpServerEnabled, isModuleNotFoundError, isPlatformOwnedObject, keysetWalk, looksLikeInternalErrorLeak, postureGatesGlobalUniques, readEnvWithDeprecation, recordGlobalUniqueAttestation, resolveAllowDegradedTenancy, resolveAllowDevPlugin, resolveAllowDriverConnectFailure, resolveMcpStdioAutoStart, resolveMultiOrgEnabled, resolveOrgLimit, resolveSandboxTimeoutMs, resolveSearchPinyinEnabled, resolveTenancyPosture, sendError, sendOk, stampSearchPinyinEnabled, unconfirmedGlobalUniques };
|
|
1098
|
+
export { type EnvelopeResponse, GLOBAL_UNIQUE_CONFIRMATION_REQUIRED, GLOBAL_UNIQUE_ISOLATED_PRESCRIPTION, type GlobalUniqueAttestation, type GlobalUniqueFinding, type IKernel, INTERNAL_ERROR_MESSAGE, type KeysetPageQuery, type KeysetWalk, type KeysetWalkOptions, type RuntimeContext, type RuntimePlugin, _resetEnvDeprecationWarnings, buildGlobalUniqueStopMessage, collectConfiguredLocales, collectGlobalUniques, declaredIndexUniqueIsGlobal, declaresServerFault, describeGlobalUniqueFinding, emitDegradedBootBanner, fieldUniqueIsGlobal, globalUniqueFindingId, isMcpServerEnabled, isModuleNotFoundError, isPlatformOwnedObject, isRelationSubObjectPhrase, isUniqueViolationError, keysetWalk, looksLikeInternalErrorLeak, matchMissingColumnOfRelation, postureGatesGlobalUniques, readEnvWithDeprecation, recordGlobalUniqueAttestation, resolveAllowDegradedTenancy, resolveAllowDevPlugin, resolveAllowDriverConnectFailure, resolveMcpStdioAutoStart, resolveMultiOrgEnabled, resolveOrgLimit, resolveSandboxTimeoutMs, resolveSearchPinyinEnabled, resolveTenancyPosture, sendError, sendOk, stampSearchPinyinEnabled, unconfirmedGlobalUniques, uniqueViolationColumn };
|
package/dist/index.js
CHANGED
|
@@ -36,8 +36,11 @@ __export(index_exports, {
|
|
|
36
36
|
isMcpServerEnabled: () => isMcpServerEnabled,
|
|
37
37
|
isModuleNotFoundError: () => isModuleNotFoundError,
|
|
38
38
|
isPlatformOwnedObject: () => isPlatformOwnedObject,
|
|
39
|
+
isRelationSubObjectPhrase: () => isRelationSubObjectPhrase,
|
|
40
|
+
isUniqueViolationError: () => isUniqueViolationError,
|
|
39
41
|
keysetWalk: () => keysetWalk,
|
|
40
42
|
looksLikeInternalErrorLeak: () => looksLikeInternalErrorLeak,
|
|
43
|
+
matchMissingColumnOfRelation: () => matchMissingColumnOfRelation,
|
|
41
44
|
postureGatesGlobalUniques: () => postureGatesGlobalUniques,
|
|
42
45
|
readEnvWithDeprecation: () => readEnvWithDeprecation,
|
|
43
46
|
recordGlobalUniqueAttestation: () => recordGlobalUniqueAttestation,
|
|
@@ -53,7 +56,8 @@ __export(index_exports, {
|
|
|
53
56
|
sendError: () => sendError,
|
|
54
57
|
sendOk: () => sendOk,
|
|
55
58
|
stampSearchPinyinEnabled: () => stampSearchPinyinEnabled,
|
|
56
|
-
unconfirmedGlobalUniques: () => unconfirmedGlobalUniques
|
|
59
|
+
unconfirmedGlobalUniques: () => unconfirmedGlobalUniques,
|
|
60
|
+
uniqueViolationColumn: () => uniqueViolationColumn
|
|
57
61
|
});
|
|
58
62
|
module.exports = __toCommonJS(index_exports);
|
|
59
63
|
|
|
@@ -280,6 +284,82 @@ function sendError(res, status, code, message, extra) {
|
|
|
280
284
|
res.status(status).json({ success: false, error: { code, message, ...extra } });
|
|
281
285
|
}
|
|
282
286
|
|
|
287
|
+
// src/relation-sub-object.ts
|
|
288
|
+
function matchMissingColumnOfRelation(message) {
|
|
289
|
+
return MISSING_COLUMN_OF_RELATION.exec(message)?.[1];
|
|
290
|
+
}
|
|
291
|
+
function isRelationSubObjectPhrase(message) {
|
|
292
|
+
return RELATION_SUB_OBJECT.test(message);
|
|
293
|
+
}
|
|
294
|
+
var MISSING_COLUMN_OF_RELATION = /column\s+["'`]([a-z0-9_]+)["'`]\s+of relation\s+\S+\s+does not exist/i;
|
|
295
|
+
var RELATION_SUB_OBJECT = /["'`][^"'`]+["'`]\s+of relation\s/i;
|
|
296
|
+
|
|
297
|
+
// src/unique-violation.ts
|
|
298
|
+
var UNIQUE_VIOLATION = {
|
|
299
|
+
codes: /* @__PURE__ */ new Set(["23505", "ER_DUP_ENTRY", "SQLITE_CONSTRAINT_UNIQUE"]),
|
|
300
|
+
errnos: /* @__PURE__ */ new Set([1062]),
|
|
301
|
+
message: /unique constraint|unique violation|duplicate key|duplicate entry/i
|
|
302
|
+
};
|
|
303
|
+
var MAX_CAUSE_DEPTH = 4;
|
|
304
|
+
function isUniqueViolationError(error) {
|
|
305
|
+
return matchesUniqueViolation(error, 0);
|
|
306
|
+
}
|
|
307
|
+
function matchesUniqueViolation(error, depth) {
|
|
308
|
+
if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH) return false;
|
|
309
|
+
if (typeof error === "string") return UNIQUE_VIOLATION.message.test(error);
|
|
310
|
+
if (typeof error !== "object") return false;
|
|
311
|
+
const err = error;
|
|
312
|
+
if (typeof err.code === "string" && UNIQUE_VIOLATION.codes.has(err.code)) return true;
|
|
313
|
+
if (typeof err.code === "number" && UNIQUE_VIOLATION.errnos.has(err.code)) return true;
|
|
314
|
+
if (typeof err.errno === "number" && UNIQUE_VIOLATION.errnos.has(err.errno)) return true;
|
|
315
|
+
if (typeof err.message === "string" && UNIQUE_VIOLATION.message.test(err.message)) return true;
|
|
316
|
+
return matchesUniqueViolation(err.cause, depth + 1);
|
|
317
|
+
}
|
|
318
|
+
var SQLITE_TARGETS = /unique constraint failed:\s*([^\n]*)/i;
|
|
319
|
+
var POSTGRES_DETAIL_TARGETS = /\bkey \(([^)]+)\)=\(/i;
|
|
320
|
+
var SQLITE_INDEX_FORM = /^index\b/i;
|
|
321
|
+
var PLAIN_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_$]*$/;
|
|
322
|
+
function bareIdentifier(raw) {
|
|
323
|
+
const stripped = raw.trim().replace(/[`"'[\]]/g, "");
|
|
324
|
+
const dot = stripped.lastIndexOf(".");
|
|
325
|
+
return dot >= 0 ? stripped.slice(dot + 1) : stripped;
|
|
326
|
+
}
|
|
327
|
+
function soleColumn(targets) {
|
|
328
|
+
const names = targets.split(",").map(bareIdentifier);
|
|
329
|
+
if (names.length !== 1) return void 0;
|
|
330
|
+
const [name] = names;
|
|
331
|
+
return PLAIN_IDENTIFIER.test(name) ? name : void 0;
|
|
332
|
+
}
|
|
333
|
+
function columnFromText(text) {
|
|
334
|
+
const sqlite = SQLITE_TARGETS.exec(text);
|
|
335
|
+
if (sqlite) {
|
|
336
|
+
const targets = sqlite[1].trim();
|
|
337
|
+
return SQLITE_INDEX_FORM.test(targets) ? void 0 : soleColumn(targets);
|
|
338
|
+
}
|
|
339
|
+
const postgres = POSTGRES_DETAIL_TARGETS.exec(text);
|
|
340
|
+
if (postgres) return soleColumn(postgres[1]);
|
|
341
|
+
return void 0;
|
|
342
|
+
}
|
|
343
|
+
function findUniqueViolationColumn(error, depth) {
|
|
344
|
+
if (error === null || error === void 0 || depth > MAX_CAUSE_DEPTH) return void 0;
|
|
345
|
+
if (typeof error === "string") return columnFromText(error);
|
|
346
|
+
if (typeof error !== "object") return void 0;
|
|
347
|
+
const err = error;
|
|
348
|
+
if (typeof err.message === "string") {
|
|
349
|
+
const fromMessage = columnFromText(err.message);
|
|
350
|
+
if (fromMessage !== void 0) return fromMessage;
|
|
351
|
+
}
|
|
352
|
+
if (typeof err.detail === "string") {
|
|
353
|
+
const fromDetail = columnFromText(err.detail);
|
|
354
|
+
if (fromDetail !== void 0) return fromDetail;
|
|
355
|
+
}
|
|
356
|
+
return findUniqueViolationColumn(err.cause, depth + 1);
|
|
357
|
+
}
|
|
358
|
+
function uniqueViolationColumn(error) {
|
|
359
|
+
if (!isUniqueViolationError(error)) return void 0;
|
|
360
|
+
return findUniqueViolationColumn(error, 0);
|
|
361
|
+
}
|
|
362
|
+
|
|
283
363
|
// src/unique-scope-install-gate.ts
|
|
284
364
|
var import_security2 = require("@objectstack/spec/security");
|
|
285
365
|
var SYS_OBJECT_PREFIXES = ["sys_", "base_"];
|
|
@@ -395,8 +475,11 @@ function postureGatesGlobalUniques(posture) {
|
|
|
395
475
|
isMcpServerEnabled,
|
|
396
476
|
isModuleNotFoundError,
|
|
397
477
|
isPlatformOwnedObject,
|
|
478
|
+
isRelationSubObjectPhrase,
|
|
479
|
+
isUniqueViolationError,
|
|
398
480
|
keysetWalk,
|
|
399
481
|
looksLikeInternalErrorLeak,
|
|
482
|
+
matchMissingColumnOfRelation,
|
|
400
483
|
postureGatesGlobalUniques,
|
|
401
484
|
readEnvWithDeprecation,
|
|
402
485
|
recordGlobalUniqueAttestation,
|
|
@@ -412,6 +495,7 @@ function postureGatesGlobalUniques(posture) {
|
|
|
412
495
|
sendError,
|
|
413
496
|
sendOk,
|
|
414
497
|
stampSearchPinyinEnabled,
|
|
415
|
-
unconfirmedGlobalUniques
|
|
498
|
+
unconfirmedGlobalUniques,
|
|
499
|
+
uniqueViolationColumn
|
|
416
500
|
});
|
|
417
501
|
//# sourceMappingURL=index.js.map
|