@ai-matrx/records 0.99.30 → 0.99.31

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.
@@ -868,4 +868,191 @@ declare function seededDataSource(index: Map<string, unknown>): {
868
868
  missed: () => boolean;
869
869
  };
870
870
 
871
- export { type BlockOutcome, DEFAULT_DOCUMENT_MAX_BYTES, DEFAULT_VALUE_MAX_BYTES, DOORS, type DoorKey, type ExportRow, Field, LANDING_SOURCE_TYPE, LANDING_TARGET_TYPES, type Landing, type LandingBlock, type LandingOutcomes, type LandingState, type LandingStore, MAPPED_SQLSTATES, type MirrorLimits, OUTPUT_KEPT_KEY, PRIMED_DOOR_TTL_MS, PRODUCED_BY_LABEL, type ParsedImport, PgError, PredictedRefusal, type PrimedBundleAnswer, type ReadFileText, ReadValue, RecordDocument, RecordsDataSource, RecordsError, RecordsResult, type RecordsSeed, type RecordsSeedAnswer, STORE_SCHEMA, StaleWriteDetail, type StoreCaller, type StoreDoorAnswer, type StoreDoorError, type StoreDoors, type SupabaseLike, TableKindFacts, Uuid, WHOLE_VALUE_SOURCE_KIND, type WholeValuePointer, announceRecordChanged, announceTableStructureChanged, archivedOrganizationId, asRecordsDataSource, blockLandedInStore, cellText, doorAbsent, doorCensus, doorExists, doorReady, dropPrimedDoorAnswers, exportCellText, exportCsv, exportMarkdown, exportXlsx, forgetPrimedTablePageBundles, importCsv, importXlsx, isRecordRemoved, landingOutcomesFor, mapPgError, mapThrownError, markRecordRemoved, markRecordRestored, onRecordChanged, onTableStructureChanged, outcomeForBlock, outputIsKept, parseCsv, predictEnvelopeRefusal, predictSizeRefusal, predictValueRefusals, predictWriteRefusals, primeDoorAnswer, primeRecordPageBundle, primeTablePageBundle, recordingDataSource, seedIndex, seedKey, seededDataSource, staleWriteDetail, storeDoors, supabaseDataSource, tableKindFacts, takePrimedTablePageBundle, toAoa, valuesAreUnconfirmed, wholeValueNotRead, wholeValueOf, wholeValueOfRead, wholeValueSize, withWholeValues };
871
+ /** A database JSON column. Nothing is assumed about it; a reader narrows what it reads. */
872
+ type Json = unknown;
873
+ /** `public.field_data_type`. */
874
+ type FieldDataType = "string" | "number" | "integer" | "boolean" | "date" | "datetime" | "json" | "array";
875
+ /** A column as the grid draws it. */
876
+ type DatasetField = {
877
+ id: string;
878
+ table_id: string;
879
+ field_name: string;
880
+ display_name: string;
881
+ data_type: FieldDataType;
882
+ field_order: number;
883
+ is_required: boolean;
884
+ is_public: boolean;
885
+ default_value: Json | null;
886
+ validation_rules: Json | null;
887
+ metadata: Json;
888
+ custom_fields: Json;
889
+ organization_id: string;
890
+ user_id: string;
891
+ created_at: string;
892
+ created_by: string | null;
893
+ updated_at: string;
894
+ updated_by: string | null;
895
+ deleted_at: string | null;
896
+ version: number;
897
+ };
898
+ /** A row as the grid holds it. */
899
+ type DatasetRow = {
900
+ id: string;
901
+ table_id: string;
902
+ data: Json;
903
+ metadata: Json;
904
+ custom_fields: Json;
905
+ is_public: boolean;
906
+ organization_id: string;
907
+ user_id: string;
908
+ source_row_ref: string | null;
909
+ created_at: string;
910
+ created_by: string | null;
911
+ updated_at: string;
912
+ updated_by: string | null;
913
+ deleted_at: string | null;
914
+ version: number;
915
+ };
916
+ type BulkInsertOp = {
917
+ op: "insert";
918
+ data: Record<string, unknown>;
919
+ };
920
+ type BulkUpdateOp = {
921
+ op: "update";
922
+ row_id: string;
923
+ /** REPLACES the row's data wholesale. Keys not in `data` are dropped. */
924
+ data: Record<string, unknown>;
925
+ /**
926
+ * The version the person saw this row at, when the caller holds it (an undo carries the version its
927
+ * own write produced). Absent = the seam's ledger of the rows it drew (`lib/records/record-versions.ts`).
928
+ */
929
+ expected_version?: number | null;
930
+ };
931
+ type BulkMergeOp = {
932
+ op: "merge";
933
+ row_id: string;
934
+ /**
935
+ * Partial update — `data = existing_data || patch`. Keys in `data` overwrite
936
+ * the row's matching keys; keys absent from `data` are preserved. Use this
937
+ * when sending only changed fields.
938
+ */
939
+ data: Record<string, unknown>;
940
+ /**
941
+ * The version the person saw this row at, when the caller holds it (an undo carries the version its
942
+ * own write produced). Absent = the seam's ledger of the rows it drew (`lib/records/record-versions.ts`).
943
+ */
944
+ expected_version?: number | null;
945
+ };
946
+ type BulkCellOp = {
947
+ op: "cell";
948
+ row_id: string;
949
+ field_name: string;
950
+ value: unknown;
951
+ /**
952
+ * The version the person saw this row at, when the caller holds it (an undo carries the version its
953
+ * own write produced). Absent = the seam's ledger of the rows it drew (`lib/records/record-versions.ts`).
954
+ */
955
+ expected_version?: number | null;
956
+ };
957
+ type BulkDeleteOp = {
958
+ op: "delete";
959
+ row_id: string;
960
+ };
961
+ type BulkOp = BulkInsertOp | BulkUpdateOp | BulkMergeOp | BulkCellOp | BulkDeleteOp;
962
+ /**
963
+ * Per-op result envelope returned inside `bulkWrite`'s `results[]`.
964
+ *
965
+ * Note: insert / update / cell / delete that succeed return the full row.
966
+ * Update / cell / delete against a row that is gone return `row_not_found`;
967
+ * update / cell / merge against a row that is in Trash return `row_in_trash`
968
+ * (with the server's own sentence in `message`). Both are soft failures — the
969
+ * rest of the batch continues. Inserts that fail RAISE and abort the batch.
970
+ */
971
+ type BulkOpError = {
972
+ error: "row_not_found" | "row_in_trash";
973
+ row_id: string;
974
+ message?: string;
975
+ };
976
+ type BulkOpResult = DatasetRow | BulkOpError;
977
+ /**
978
+ * Narrow a bulk-write result slot to the error variant.
979
+ * Successful results carry the full DatasetRow shape (no discriminator key
980
+ * on the success side, so consumers narrow via this guard).
981
+ */
982
+ declare function isBulkOpError(r: BulkOpResult): r is BulkOpError;
983
+ /**
984
+ * One plain sentence for the rows a batch could not change — the ONE wording
985
+ * every bulk surface uses. A row in Trash is named as such (it can be restored),
986
+ * never reported as "could not be found".
987
+ */
988
+ declare function describeBulkFailures(failed: BulkOpError[]): string;
989
+ type BulkWriteResponse = {
990
+ table_id: string;
991
+ count: number;
992
+ results: BulkOpResult[];
993
+ };
994
+ type ServiceOk<T> = {
995
+ success: true;
996
+ data: T;
997
+ };
998
+ /**
999
+ * THE STORE'S OWN REFUSAL, kept whole (lane FIX-15, 2026-09-23).
1000
+ *
1001
+ * `error` is `PostgrestError.message` and nothing else, so a refusal written as
1002
+ * three parts — what happened, what the column is, what to do instead — reached
1003
+ * the screen as one third of itself, and the other two thirds (DETAIL and HINT)
1004
+ * were thrown away in this envelope. On production a name typed into a relation
1005
+ * column was refused by the store with a perfectly good sentence
1006
+ * and the person saw nothing usable.
1007
+ *
1008
+ * `refusal` carries the whole thing in the shape every Matrx screen already
1009
+ * knows how to draw (`RefusalNotice` / `RefusalLine` from `@ai-matrx/records-ui`,
1010
+ * which run it through `plainWords` so no machine identity is ever printed at a
1011
+ * person). `error` stays exactly what it was for the callers that print a line.
1012
+ */
1013
+ type ServiceErr = {
1014
+ success: false;
1015
+ error: string;
1016
+ refusal?: RecordsError;
1017
+ };
1018
+ type ServiceResult<T> = ServiceOk<T> | ServiceErr;
1019
+ /**
1020
+ * Narrow a ServiceResult to the failure variant. Use instead of `!result.success`
1021
+ * inside generic functions where TS's narrow through `Promise<ServiceResult<T>>`
1022
+ * sometimes fails to discriminate the union members reliably.
1023
+ */
1024
+ declare function isServiceFailure<T>(r: ServiceResult<T>): r is ServiceErr;
1025
+ /**
1026
+ * Infer a table column's data type for a single value. Used by both the
1027
+ * CSV/Excel import path and the JSON-to-table path. The returned strings
1028
+ * align with `VALID_DATA_TYPES` in `table-utils.ts`.
1029
+ */
1030
+ declare function inferDataType(value: unknown): string;
1031
+ /**
1032
+ * Sanitize a display name into a valid field name
1033
+ * Converts to lowercase, replaces special chars with underscores, follows snake_case
1034
+ *
1035
+ * @param displayName - The user-entered display name
1036
+ * @returns Sanitized field name in snake_case format
1037
+ *
1038
+ * @example
1039
+ * sanitizeFieldName("Total Revenue") // returns "total_revenue"
1040
+ * sanitizeFieldName("Price ($)") // returns "price"
1041
+ * sanitizeFieldName("2024 Sales") // returns "_2024_sales"
1042
+ */
1043
+ declare function sanitizeFieldName(displayName: string): string;
1044
+ /**
1045
+ * Validate that a field name follows the required format
1046
+ * Must start with lowercase letter, contain only lowercase letters, numbers, and underscores
1047
+ *
1048
+ * @param fieldName - The field name to validate
1049
+ * @returns true if valid, false otherwise
1050
+ *
1051
+ * @example
1052
+ * validateFieldName("total_revenue") // returns true
1053
+ * validateFieldName("Total Revenue") // returns false
1054
+ * validateFieldName("123_sales") // returns false
1055
+ */
1056
+ declare function validateFieldName(fieldName: string): boolean;
1057
+
1058
+ export { type BlockOutcome, type BulkCellOp, type BulkDeleteOp, type BulkInsertOp, type BulkMergeOp, type BulkOp, type BulkOpError, type BulkOpResult, type BulkUpdateOp, type BulkWriteResponse, DEFAULT_DOCUMENT_MAX_BYTES, DEFAULT_VALUE_MAX_BYTES, DOORS, type DatasetField, type DatasetRow, type DoorKey, type ExportRow, Field, type FieldDataType, type Json, LANDING_SOURCE_TYPE, LANDING_TARGET_TYPES, type Landing, type LandingBlock, type LandingOutcomes, type LandingState, type LandingStore, MAPPED_SQLSTATES, type MirrorLimits, OUTPUT_KEPT_KEY, PRIMED_DOOR_TTL_MS, PRODUCED_BY_LABEL, type ParsedImport, PgError, PredictedRefusal, type PrimedBundleAnswer, type ReadFileText, ReadValue, RecordDocument, RecordsDataSource, RecordsError, RecordsResult, type RecordsSeed, type RecordsSeedAnswer, STORE_SCHEMA, type ServiceErr, type ServiceOk, type ServiceResult, StaleWriteDetail, type StoreCaller, type StoreDoorAnswer, type StoreDoorError, type StoreDoors, type SupabaseLike, TableKindFacts, Uuid, WHOLE_VALUE_SOURCE_KIND, type WholeValuePointer, announceRecordChanged, announceTableStructureChanged, archivedOrganizationId, asRecordsDataSource, blockLandedInStore, cellText, describeBulkFailures, doorAbsent, doorCensus, doorExists, doorReady, dropPrimedDoorAnswers, exportCellText, exportCsv, exportMarkdown, exportXlsx, forgetPrimedTablePageBundles, importCsv, importXlsx, inferDataType, isBulkOpError, isRecordRemoved, isServiceFailure, landingOutcomesFor, mapPgError, mapThrownError, markRecordRemoved, markRecordRestored, onRecordChanged, onTableStructureChanged, outcomeForBlock, outputIsKept, parseCsv, predictEnvelopeRefusal, predictSizeRefusal, predictValueRefusals, predictWriteRefusals, primeDoorAnswer, primeRecordPageBundle, primeTablePageBundle, recordingDataSource, sanitizeFieldName, seedIndex, seedKey, seededDataSource, staleWriteDetail, storeDoors, supabaseDataSource, tableKindFacts, takePrimedTablePageBundle, toAoa, validateFieldName, valuesAreUnconfirmed, wholeValueNotRead, wholeValueOf, wholeValueOfRead, wholeValueSize, withWholeValues };
@@ -868,4 +868,191 @@ declare function seededDataSource(index: Map<string, unknown>): {
868
868
  missed: () => boolean;
869
869
  };
870
870
 
871
- export { type BlockOutcome, DEFAULT_DOCUMENT_MAX_BYTES, DEFAULT_VALUE_MAX_BYTES, DOORS, type DoorKey, type ExportRow, Field, LANDING_SOURCE_TYPE, LANDING_TARGET_TYPES, type Landing, type LandingBlock, type LandingOutcomes, type LandingState, type LandingStore, MAPPED_SQLSTATES, type MirrorLimits, OUTPUT_KEPT_KEY, PRIMED_DOOR_TTL_MS, PRODUCED_BY_LABEL, type ParsedImport, PgError, PredictedRefusal, type PrimedBundleAnswer, type ReadFileText, ReadValue, RecordDocument, RecordsDataSource, RecordsError, RecordsResult, type RecordsSeed, type RecordsSeedAnswer, STORE_SCHEMA, StaleWriteDetail, type StoreCaller, type StoreDoorAnswer, type StoreDoorError, type StoreDoors, type SupabaseLike, TableKindFacts, Uuid, WHOLE_VALUE_SOURCE_KIND, type WholeValuePointer, announceRecordChanged, announceTableStructureChanged, archivedOrganizationId, asRecordsDataSource, blockLandedInStore, cellText, doorAbsent, doorCensus, doorExists, doorReady, dropPrimedDoorAnswers, exportCellText, exportCsv, exportMarkdown, exportXlsx, forgetPrimedTablePageBundles, importCsv, importXlsx, isRecordRemoved, landingOutcomesFor, mapPgError, mapThrownError, markRecordRemoved, markRecordRestored, onRecordChanged, onTableStructureChanged, outcomeForBlock, outputIsKept, parseCsv, predictEnvelopeRefusal, predictSizeRefusal, predictValueRefusals, predictWriteRefusals, primeDoorAnswer, primeRecordPageBundle, primeTablePageBundle, recordingDataSource, seedIndex, seedKey, seededDataSource, staleWriteDetail, storeDoors, supabaseDataSource, tableKindFacts, takePrimedTablePageBundle, toAoa, valuesAreUnconfirmed, wholeValueNotRead, wholeValueOf, wholeValueOfRead, wholeValueSize, withWholeValues };
871
+ /** A database JSON column. Nothing is assumed about it; a reader narrows what it reads. */
872
+ type Json = unknown;
873
+ /** `public.field_data_type`. */
874
+ type FieldDataType = "string" | "number" | "integer" | "boolean" | "date" | "datetime" | "json" | "array";
875
+ /** A column as the grid draws it. */
876
+ type DatasetField = {
877
+ id: string;
878
+ table_id: string;
879
+ field_name: string;
880
+ display_name: string;
881
+ data_type: FieldDataType;
882
+ field_order: number;
883
+ is_required: boolean;
884
+ is_public: boolean;
885
+ default_value: Json | null;
886
+ validation_rules: Json | null;
887
+ metadata: Json;
888
+ custom_fields: Json;
889
+ organization_id: string;
890
+ user_id: string;
891
+ created_at: string;
892
+ created_by: string | null;
893
+ updated_at: string;
894
+ updated_by: string | null;
895
+ deleted_at: string | null;
896
+ version: number;
897
+ };
898
+ /** A row as the grid holds it. */
899
+ type DatasetRow = {
900
+ id: string;
901
+ table_id: string;
902
+ data: Json;
903
+ metadata: Json;
904
+ custom_fields: Json;
905
+ is_public: boolean;
906
+ organization_id: string;
907
+ user_id: string;
908
+ source_row_ref: string | null;
909
+ created_at: string;
910
+ created_by: string | null;
911
+ updated_at: string;
912
+ updated_by: string | null;
913
+ deleted_at: string | null;
914
+ version: number;
915
+ };
916
+ type BulkInsertOp = {
917
+ op: "insert";
918
+ data: Record<string, unknown>;
919
+ };
920
+ type BulkUpdateOp = {
921
+ op: "update";
922
+ row_id: string;
923
+ /** REPLACES the row's data wholesale. Keys not in `data` are dropped. */
924
+ data: Record<string, unknown>;
925
+ /**
926
+ * The version the person saw this row at, when the caller holds it (an undo carries the version its
927
+ * own write produced). Absent = the seam's ledger of the rows it drew (`lib/records/record-versions.ts`).
928
+ */
929
+ expected_version?: number | null;
930
+ };
931
+ type BulkMergeOp = {
932
+ op: "merge";
933
+ row_id: string;
934
+ /**
935
+ * Partial update — `data = existing_data || patch`. Keys in `data` overwrite
936
+ * the row's matching keys; keys absent from `data` are preserved. Use this
937
+ * when sending only changed fields.
938
+ */
939
+ data: Record<string, unknown>;
940
+ /**
941
+ * The version the person saw this row at, when the caller holds it (an undo carries the version its
942
+ * own write produced). Absent = the seam's ledger of the rows it drew (`lib/records/record-versions.ts`).
943
+ */
944
+ expected_version?: number | null;
945
+ };
946
+ type BulkCellOp = {
947
+ op: "cell";
948
+ row_id: string;
949
+ field_name: string;
950
+ value: unknown;
951
+ /**
952
+ * The version the person saw this row at, when the caller holds it (an undo carries the version its
953
+ * own write produced). Absent = the seam's ledger of the rows it drew (`lib/records/record-versions.ts`).
954
+ */
955
+ expected_version?: number | null;
956
+ };
957
+ type BulkDeleteOp = {
958
+ op: "delete";
959
+ row_id: string;
960
+ };
961
+ type BulkOp = BulkInsertOp | BulkUpdateOp | BulkMergeOp | BulkCellOp | BulkDeleteOp;
962
+ /**
963
+ * Per-op result envelope returned inside `bulkWrite`'s `results[]`.
964
+ *
965
+ * Note: insert / update / cell / delete that succeed return the full row.
966
+ * Update / cell / delete against a row that is gone return `row_not_found`;
967
+ * update / cell / merge against a row that is in Trash return `row_in_trash`
968
+ * (with the server's own sentence in `message`). Both are soft failures — the
969
+ * rest of the batch continues. Inserts that fail RAISE and abort the batch.
970
+ */
971
+ type BulkOpError = {
972
+ error: "row_not_found" | "row_in_trash";
973
+ row_id: string;
974
+ message?: string;
975
+ };
976
+ type BulkOpResult = DatasetRow | BulkOpError;
977
+ /**
978
+ * Narrow a bulk-write result slot to the error variant.
979
+ * Successful results carry the full DatasetRow shape (no discriminator key
980
+ * on the success side, so consumers narrow via this guard).
981
+ */
982
+ declare function isBulkOpError(r: BulkOpResult): r is BulkOpError;
983
+ /**
984
+ * One plain sentence for the rows a batch could not change — the ONE wording
985
+ * every bulk surface uses. A row in Trash is named as such (it can be restored),
986
+ * never reported as "could not be found".
987
+ */
988
+ declare function describeBulkFailures(failed: BulkOpError[]): string;
989
+ type BulkWriteResponse = {
990
+ table_id: string;
991
+ count: number;
992
+ results: BulkOpResult[];
993
+ };
994
+ type ServiceOk<T> = {
995
+ success: true;
996
+ data: T;
997
+ };
998
+ /**
999
+ * THE STORE'S OWN REFUSAL, kept whole (lane FIX-15, 2026-09-23).
1000
+ *
1001
+ * `error` is `PostgrestError.message` and nothing else, so a refusal written as
1002
+ * three parts — what happened, what the column is, what to do instead — reached
1003
+ * the screen as one third of itself, and the other two thirds (DETAIL and HINT)
1004
+ * were thrown away in this envelope. On production a name typed into a relation
1005
+ * column was refused by the store with a perfectly good sentence
1006
+ * and the person saw nothing usable.
1007
+ *
1008
+ * `refusal` carries the whole thing in the shape every Matrx screen already
1009
+ * knows how to draw (`RefusalNotice` / `RefusalLine` from `@ai-matrx/records-ui`,
1010
+ * which run it through `plainWords` so no machine identity is ever printed at a
1011
+ * person). `error` stays exactly what it was for the callers that print a line.
1012
+ */
1013
+ type ServiceErr = {
1014
+ success: false;
1015
+ error: string;
1016
+ refusal?: RecordsError;
1017
+ };
1018
+ type ServiceResult<T> = ServiceOk<T> | ServiceErr;
1019
+ /**
1020
+ * Narrow a ServiceResult to the failure variant. Use instead of `!result.success`
1021
+ * inside generic functions where TS's narrow through `Promise<ServiceResult<T>>`
1022
+ * sometimes fails to discriminate the union members reliably.
1023
+ */
1024
+ declare function isServiceFailure<T>(r: ServiceResult<T>): r is ServiceErr;
1025
+ /**
1026
+ * Infer a table column's data type for a single value. Used by both the
1027
+ * CSV/Excel import path and the JSON-to-table path. The returned strings
1028
+ * align with `VALID_DATA_TYPES` in `table-utils.ts`.
1029
+ */
1030
+ declare function inferDataType(value: unknown): string;
1031
+ /**
1032
+ * Sanitize a display name into a valid field name
1033
+ * Converts to lowercase, replaces special chars with underscores, follows snake_case
1034
+ *
1035
+ * @param displayName - The user-entered display name
1036
+ * @returns Sanitized field name in snake_case format
1037
+ *
1038
+ * @example
1039
+ * sanitizeFieldName("Total Revenue") // returns "total_revenue"
1040
+ * sanitizeFieldName("Price ($)") // returns "price"
1041
+ * sanitizeFieldName("2024 Sales") // returns "_2024_sales"
1042
+ */
1043
+ declare function sanitizeFieldName(displayName: string): string;
1044
+ /**
1045
+ * Validate that a field name follows the required format
1046
+ * Must start with lowercase letter, contain only lowercase letters, numbers, and underscores
1047
+ *
1048
+ * @param fieldName - The field name to validate
1049
+ * @returns true if valid, false otherwise
1050
+ *
1051
+ * @example
1052
+ * validateFieldName("total_revenue") // returns true
1053
+ * validateFieldName("Total Revenue") // returns false
1054
+ * validateFieldName("123_sales") // returns false
1055
+ */
1056
+ declare function validateFieldName(fieldName: string): boolean;
1057
+
1058
+ export { type BlockOutcome, type BulkCellOp, type BulkDeleteOp, type BulkInsertOp, type BulkMergeOp, type BulkOp, type BulkOpError, type BulkOpResult, type BulkUpdateOp, type BulkWriteResponse, DEFAULT_DOCUMENT_MAX_BYTES, DEFAULT_VALUE_MAX_BYTES, DOORS, type DatasetField, type DatasetRow, type DoorKey, type ExportRow, Field, type FieldDataType, type Json, LANDING_SOURCE_TYPE, LANDING_TARGET_TYPES, type Landing, type LandingBlock, type LandingOutcomes, type LandingState, type LandingStore, MAPPED_SQLSTATES, type MirrorLimits, OUTPUT_KEPT_KEY, PRIMED_DOOR_TTL_MS, PRODUCED_BY_LABEL, type ParsedImport, PgError, PredictedRefusal, type PrimedBundleAnswer, type ReadFileText, ReadValue, RecordDocument, RecordsDataSource, RecordsError, RecordsResult, type RecordsSeed, type RecordsSeedAnswer, STORE_SCHEMA, type ServiceErr, type ServiceOk, type ServiceResult, StaleWriteDetail, type StoreCaller, type StoreDoorAnswer, type StoreDoorError, type StoreDoors, type SupabaseLike, TableKindFacts, Uuid, WHOLE_VALUE_SOURCE_KIND, type WholeValuePointer, announceRecordChanged, announceTableStructureChanged, archivedOrganizationId, asRecordsDataSource, blockLandedInStore, cellText, describeBulkFailures, doorAbsent, doorCensus, doorExists, doorReady, dropPrimedDoorAnswers, exportCellText, exportCsv, exportMarkdown, exportXlsx, forgetPrimedTablePageBundles, importCsv, importXlsx, inferDataType, isBulkOpError, isRecordRemoved, isServiceFailure, landingOutcomesFor, mapPgError, mapThrownError, markRecordRemoved, markRecordRestored, onRecordChanged, onTableStructureChanged, outcomeForBlock, outputIsKept, parseCsv, predictEnvelopeRefusal, predictSizeRefusal, predictValueRefusals, predictWriteRefusals, primeDoorAnswer, primeRecordPageBundle, primeTablePageBundle, recordingDataSource, sanitizeFieldName, seedIndex, seedKey, seededDataSource, staleWriteDetail, storeDoors, supabaseDataSource, tableKindFacts, takePrimedTablePageBundle, toAoa, validateFieldName, valuesAreUnconfirmed, wholeValueNotRead, wholeValueOf, wholeValueOfRead, wholeValueSize, withWholeValues };
@@ -12059,6 +12059,64 @@ function seededDataSource(index) {
12059
12059
  };
12060
12060
  return { source, missed: () => missed };
12061
12061
  }
12062
+
12063
+ // src/core/table-logic.ts
12064
+ function isBulkOpError(r) {
12065
+ return typeof r === "object" && r !== null && "error" in r;
12066
+ }
12067
+ function describeBulkFailures(failed) {
12068
+ const inTrash = failed.filter((f) => f.error === "row_in_trash").length;
12069
+ const missing = failed.length - inTrash;
12070
+ const parts = [];
12071
+ if (inTrash > 0) {
12072
+ parts.push(
12073
+ `${inTrash} row${inTrash === 1 ? " is" : "s are"} in Trash \u2014 restore ${inTrash === 1 ? "it" : "them"} from Trash to edit`
12074
+ );
12075
+ }
12076
+ if (missing > 0) {
12077
+ parts.push(
12078
+ `${missing} row${missing === 1 ? "" : "s"} could not be found \u2014 ${missing === 1 ? "it" : "they"} may have been removed by someone else`
12079
+ );
12080
+ }
12081
+ return `${parts.join("; ")}.`;
12082
+ }
12083
+ function isServiceFailure(r) {
12084
+ return r.success === false;
12085
+ }
12086
+ var DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
12087
+ var DATETIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}/;
12088
+ function inferDataType(value) {
12089
+ if (value === null || value === void 0 || value === "") return "string";
12090
+ if (typeof value === "boolean") return "boolean";
12091
+ if (typeof value === "number") {
12092
+ return Number.isInteger(value) ? "integer" : "number";
12093
+ }
12094
+ if (typeof value === "object") {
12095
+ return Array.isArray(value) ? "array" : "json";
12096
+ }
12097
+ const str2 = String(value);
12098
+ const num2 = Number(str2);
12099
+ if (!isNaN(num2) && str2.trim() !== "") {
12100
+ return Number.isInteger(num2) ? "integer" : "number";
12101
+ }
12102
+ const lower = str2.toLowerCase().trim();
12103
+ if (lower === "true" || lower === "false") return "boolean";
12104
+ if (DATE_PATTERN.test(str2)) return "date";
12105
+ if (DATETIME_PATTERN.test(str2)) return "datetime";
12106
+ return "string";
12107
+ }
12108
+ function sanitizeFieldName(displayName) {
12109
+ if (!displayName || typeof displayName !== "string") {
12110
+ return "";
12111
+ }
12112
+ return displayName.toLowerCase().trim().replace(/[^a-z0-9\s_]/g, "").replace(/\s+/g, "_").replace(/^_+|_+$/g, "").replace(/_+/g, "_").replace(/^(\d)/, "_$1");
12113
+ }
12114
+ function validateFieldName(fieldName) {
12115
+ if (!fieldName || typeof fieldName !== "string") {
12116
+ return false;
12117
+ }
12118
+ return /^[a-z][a-z0-9_]*$/.test(fieldName);
12119
+ }
12062
12120
  export {
12063
12121
  ABSENCE_REASONS,
12064
12122
  ACTOR_VOCABULARY,
@@ -12189,6 +12247,7 @@ export {
12189
12247
  declareDrillDefinition,
12190
12248
  declareTable,
12191
12249
  defaultOpLedger,
12250
+ describeBulkFailures,
12192
12251
  doorAbsent,
12193
12252
  doorCensus,
12194
12253
  doorExists,
@@ -12226,11 +12285,13 @@ export {
12226
12285
  importCsv,
12227
12286
  importXlsx,
12228
12287
  indexedDbStore,
12288
+ inferDataType,
12229
12289
  intersectIds,
12230
12290
  isAPersonsRefusal,
12231
12291
  isAddressValue,
12232
12292
  isArchiveLane,
12233
12293
  isAutonumberField,
12294
+ isBulkOpError,
12234
12295
  isButtonField,
12235
12296
  isDecided,
12236
12297
  isEntityReferenceConfig,
@@ -12244,6 +12305,7 @@ export {
12244
12305
  isRecordsErr,
12245
12306
  isReverseField,
12246
12307
  isRuleFilter,
12308
+ isServiceFailure,
12247
12309
  isShownTo,
12248
12310
  isTableKind,
12249
12311
  isTheChosen,
@@ -12328,6 +12390,7 @@ export {
12328
12390
  rulesWithTopStar,
12329
12391
  safeLinkHref,
12330
12392
  sameDocument,
12393
+ sanitizeFieldName,
12331
12394
  scopeChip,
12332
12395
  seedIndex,
12333
12396
  seedKey,
@@ -12356,6 +12419,7 @@ export {
12356
12419
  typedMatchScore,
12357
12420
  typedTimeText,
12358
12421
  unwrapRecords,
12422
+ validateFieldName,
12359
12423
  valueConverts,
12360
12424
  valuesAreUnconfirmed,
12361
12425
  whereIdOpensPort,