@atscript/db 0.1.115 → 0.1.117

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.
@@ -0,0 +1,14 @@
1
+ //#region src/shared/consts.ts
2
+ /**
3
+ * Space name used when a model has no `@db.space` annotation. The same
4
+ * default is used by the ambient space registry in `@atscript/moost-db`
5
+ * (which re-exports this constant).
6
+ */
7
+ const DEFAULT_DB_SPACE = "default";
8
+ //#endregion
9
+ Object.defineProperty(exports, "DEFAULT_DB_SPACE", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return DEFAULT_DB_SPACE;
13
+ }
14
+ });
@@ -0,0 +1,9 @@
1
+ //#region src/shared/consts.ts
2
+ /**
3
+ * Space name used when a model has no `@db.space` annotation. The same
4
+ * default is used by the ambient space registry in `@atscript/moost-db`
5
+ * (which re-exports this constant).
6
+ */
7
+ const DEFAULT_DB_SPACE = "default";
8
+ //#endregion
9
+ export { DEFAULT_DB_SPACE as t };
@@ -2063,7 +2063,7 @@ var AtscriptDbReadable = class {
2063
2063
  * Public entry point for relation loading. Used by adapters for nested $with delegation.
2064
2064
  */
2065
2065
  async loadRelations(rows, withRelations) {
2066
- const { loadRelationsImpl } = await Promise.resolve().then(() => require("./relation-loader-Desvk9Ql.cjs")).then((n) => n.relation_loader_exports);
2066
+ const { loadRelationsImpl } = await Promise.resolve().then(() => require("./relation-loader-BnUgJsUG.cjs")).then((n) => n.relation_loader_exports);
2067
2067
  return loadRelationsImpl(rows, withRelations, this);
2068
2068
  }
2069
2069
  /**
package/dist/index.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_db_error = require("./db-error-DXwEzmYJ.cjs");
3
- const require_db_view = require("./db-view-UfGVUAol.cjs");
3
+ const require_db_view = require("./db-view-DnWm-ddS.cjs");
4
+ const require_consts = require("./consts-BzRfCcH2.cjs");
4
5
  const require_ops = require("./ops.cjs");
5
6
  const require_validator = require("./validator-BSk8lPH1.cjs");
6
7
  let node_crypto = require("node:crypto");
@@ -355,6 +356,7 @@ exports.AtscriptDbTable = require_db_view.AtscriptDbTable;
355
356
  exports.AtscriptDbView = require_db_view.AtscriptDbView;
356
357
  exports.BaseDbAdapter = require_db_view.BaseDbAdapter;
357
358
  exports.CasExhaustedError = require_db_error.CasExhaustedError;
359
+ exports.DEFAULT_DB_SPACE = require_consts.DEFAULT_DB_SPACE;
358
360
  exports.DbEncryption = DbEncryption;
359
361
  exports.DbError = require_db_error.DbError;
360
362
  exports.DbSpace = DbSpace;
package/dist/index.d.cts CHANGED
@@ -5,6 +5,14 @@ import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-val
5
5
  import { c as TArrayPatch, i as buildValidationContext, l as TDbPatch, n as ValidatorMode, o as forceNavNonOptional, r as buildDbValidator, s as isNavRelation, t as ValidationContext, u as getKeyProps } from "./validator-Crqe6vRW.cjs";
6
6
  import { AggregateQuery as AggregateQuery$1, FilterExpr as FilterExpr$1, FilterVisitor, Uniquery as Uniquery$1, computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
7
7
 
8
+ //#region src/shared/consts.d.ts
9
+ /**
10
+ * Space name used when a model has no `@db.space` annotation. The same
11
+ * default is used by the ambient space registry in `@atscript/moost-db`
12
+ * (which re-exports this constant).
13
+ */
14
+ declare const DEFAULT_DB_SPACE = "default";
15
+ //#endregion
8
16
  //#region src/strategies/relational-field-mapper.d.ts
9
17
  /**
10
18
  * Field mapper for relational adapters (e.g. SQLite, MySQL).
@@ -229,4 +237,4 @@ declare function createFailureCollector(what: string): {
229
237
  throwIfAny: () => void;
230
238
  };
231
239
  //#endregion
232
- export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, CasExhaustedError, type DbControls, DbEncryption, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, type FlatOf, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, type PrimaryKeyOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCas, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbEncryptionOptions, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbSpaceOptions, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TIdentification, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithOptimisticRetryOptions, type WithRelation, assertGeoPoint, assertNoVersionWrites, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, createFailureCollector, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, guardAggregate, guardFilter, guardQuery, isDbFieldOp, isGeoIndexableType, isGeoPointType, isNavRelation, isPrimitive, resolveDesignType, separateCas, separateFieldOps, translateQueryTree, walkFilter, withOptimisticRetry };
240
+ export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, CasExhaustedError, DEFAULT_DB_SPACE, type DbControls, DbEncryption, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, type FlatOf, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, type PrimaryKeyOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCas, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbEncryptionOptions, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbSpaceOptions, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TIdentification, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithOptimisticRetryOptions, type WithRelation, assertGeoPoint, assertNoVersionWrites, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, createFailureCollector, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, guardAggregate, guardFilter, guardQuery, isDbFieldOp, isGeoIndexableType, isGeoPointType, isNavRelation, isPrimitive, resolveDesignType, separateCas, separateFieldOps, translateQueryTree, walkFilter, withOptimisticRetry };
package/dist/index.d.mts CHANGED
@@ -5,6 +5,14 @@ import { n as createDbValidatorPlugin, t as DbValidationContext } from "./db-val
5
5
  import { c as TArrayPatch, i as buildValidationContext, l as TDbPatch, n as ValidatorMode, o as forceNavNonOptional, r as buildDbValidator, s as isNavRelation, t as ValidationContext, u as getKeyProps } from "./validator-Crqe6vRW.mjs";
6
6
  import { AggregateQuery as AggregateQuery$1, FilterExpr as FilterExpr$1, FilterVisitor, Uniquery as Uniquery$1, computeInsights, isPrimitive, walkFilter } from "@uniqu/core";
7
7
 
8
+ //#region src/shared/consts.d.ts
9
+ /**
10
+ * Space name used when a model has no `@db.space` annotation. The same
11
+ * default is used by the ambient space registry in `@atscript/moost-db`
12
+ * (which re-exports this constant).
13
+ */
14
+ declare const DEFAULT_DB_SPACE = "default";
15
+ //#endregion
8
16
  //#region src/strategies/relational-field-mapper.d.ts
9
17
  /**
10
18
  * Field mapper for relational adapters (e.g. SQLite, MySQL).
@@ -229,4 +237,4 @@ declare function createFailureCollector(what: string): {
229
237
  throwIfAny: () => void;
230
238
  };
231
239
  //#endregion
232
- export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, CasExhaustedError, type DbControls, DbEncryption, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, type FlatOf, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, type PrimaryKeyOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCas, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbEncryptionOptions, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbSpaceOptions, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TIdentification, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithOptimisticRetryOptions, type WithRelation, assertGeoPoint, assertNoVersionWrites, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, createFailureCollector, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, guardAggregate, guardFilter, guardQuery, isDbFieldOp, isGeoIndexableType, isGeoPointType, isNavRelation, isPrimitive, resolveDesignType, separateCas, separateFieldOps, translateQueryTree, walkFilter, withOptimisticRetry };
240
+ export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, type AggregateControls, type AggregateExpr, type AggregateFn, type AggregateQuery, type AggregateResult, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, type AtscriptDbWritable, type AtscriptQueryComparison, type AtscriptQueryFieldRef, type AtscriptQueryNode, type AtscriptRef, BaseDbAdapter, CasExhaustedError, DEFAULT_DB_SPACE, type DbControls, DbEncryption, DbError, type DbErrorCode, type DbQuery, type DbResponse, DbSpace, type DbValidationContext, DocumentFieldMapper, FieldMappingStrategy, type FieldOpsFor, type FilterExpr, type FilterVisitor, type FlatOf, IntegrityStrategy, NativeIntegrity, type NavPropsOf, NoopLogger, type OwnPropsOf, type PrimaryKeyOf, RelationalFieldMapper, type TAdapterFactory, type TArrayPatch, type TCascadeResolver, type TCascadeTarget, type TColumnDiff, type TCrudOp, type TCrudPermissions, type TDbActionInfo, type TDbActionIntent, type TDbActionLevel, type TDbActionProcessor, type TDbCas, type TDbCollation, type TDbDefaultFn, type TDbDefaultValue, type TDbDeleteResult, type TDbEncryptionOptions, type TDbFieldMeta, type TDbFieldOp, type TDbForeignKey, type TDbIndex, type TDbIndexField, type TDbIndexType, type TDbInsertManyResult, type TDbInsertResult, type TDbPatch, type TDbReferentialAction, type TDbRelation, type TDbSpaceOptions, type TDbStorageType, type TDbUpdateResult, type TExistingColumn, type TExistingTableOption, type TFieldMeta, type TFieldOps, type TFkLookupResolver, type TFkLookupTarget, type TGenericLogger, type TIdDescriptor, type TIdentification, type TMetaResponse, type TMetadataOverrides, type TRelationInfo, type TSearchIndexInfo, type TSyncColumnResult, type TTableOptionDiff, type TTableResolver, type TValueFormatterPair, type TViewColumnMapping, type TViewJoin, type TViewPlan, type TWriteTableResolver, TableMetadata, type TypedWithRelation, UniquSelect, type Uniquery, type UniqueryControls, type ValidationContext, type ValidatorMode, type WithOptimisticRetryOptions, type WithRelation, assertGeoPoint, assertNoVersionWrites, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, createFailureCollector, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, guardAggregate, guardFilter, guardQuery, isDbFieldOp, isGeoIndexableType, isGeoPointType, isNavRelation, isPrimitive, resolveDesignType, separateCas, separateFieldOps, translateQueryTree, walkFilter, withOptimisticRetry };
package/dist/index.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { n as DbError, t as CasExhaustedError } from "./db-error-BHPXOKzc.mjs";
2
2
  import { C as NoopLogger, S as isGeoPointType, _ as DocumentFieldMapper, a as ApplicationIntegrity, b as TableMetadata, c as IntegrityStrategy, d as resolveDesignType, f as assertGeoPoint, g as RelationalFieldMapper, h as guardQuery, i as decomposePatch, l as NativeIntegrity, m as guardFilter, n as AtscriptDbTable, o as BaseDbAdapter, p as guardAggregate, r as assertNoVersionWrites, s as createFailureCollector, t as AtscriptDbView, u as AtscriptDbReadable, v as FieldMappingStrategy, x as isGeoIndexableType, y as UniquSelect } from "./db-view-BllUecjK.mjs";
3
+ import { t as DEFAULT_DB_SPACE } from "./consts-C_-5_pFq.mjs";
3
4
  import { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, getDbFieldOp, isDbFieldOp, separateCas, separateFieldOps } from "./ops.mjs";
4
5
  import { a as isNavRelation, i as forceNavNonOptional, n as buildValidationContext, o as createDbValidatorPlugin, s as getKeyProps, t as buildDbValidator } from "./validator-C7plt6Kf.mjs";
5
6
  import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
@@ -339,4 +340,4 @@ function translateQueryTree(node, resolveField) {
339
340
  return { [leftField]: { [comp.op]: comp.right } };
340
341
  }
341
342
  //#endregion
342
- export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, BaseDbAdapter, CasExhaustedError, DbEncryption, DbError, DbSpace, DocumentFieldMapper, FieldMappingStrategy, IntegrityStrategy, NativeIntegrity, NoopLogger, RelationalFieldMapper, TableMetadata, UniquSelect, assertGeoPoint, assertNoVersionWrites, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, createFailureCollector, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, guardAggregate, guardFilter, guardQuery, isDbFieldOp, isGeoIndexableType, isGeoPointType, isNavRelation, isPrimitive, resolveDesignType, separateCas, separateFieldOps, translateQueryTree, walkFilter, withOptimisticRetry };
343
+ export { $cas, $dec, $inc, $insert, $mul, $remove, $replace, $update, $upsert, ApplicationIntegrity, AtscriptDbReadable, AtscriptDbTable, AtscriptDbView, BaseDbAdapter, CasExhaustedError, DEFAULT_DB_SPACE, DbEncryption, DbError, DbSpace, DocumentFieldMapper, FieldMappingStrategy, IntegrityStrategy, NativeIntegrity, NoopLogger, RelationalFieldMapper, TableMetadata, UniquSelect, assertGeoPoint, assertNoVersionWrites, buildDbValidator, buildValidationContext, computeInsights, createDbValidatorPlugin, createFailureCollector, decomposePatch, forceNavNonOptional, getDbFieldOp, getKeyProps, guardAggregate, guardFilter, guardQuery, isDbFieldOp, isGeoIndexableType, isGeoPointType, isNavRelation, isPrimitive, resolveDesignType, separateCas, separateFieldOps, translateQueryTree, walkFilter, withOptimisticRetry };
package/dist/plugin.cjs CHANGED
@@ -2,8 +2,132 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __exportAll = (all, no_symbols) => {
13
+ let target = {};
14
+ for (var name in all) __defProp(target, name, {
15
+ get: all[name],
16
+ enumerable: true
17
+ });
18
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
19
+ return target;
20
+ };
21
+ var __copyProps = (to, from, except, desc) => {
22
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
23
+ key = keys[i];
24
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
25
+ get: ((k) => from[k]).bind(null, key),
26
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
27
+ });
28
+ }
29
+ return to;
30
+ };
31
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
32
+ value: mod,
33
+ enumerable: true
34
+ }) : target, mod));
35
+ require("./consts-BzRfCcH2.cjs");
5
36
  const require_validation_utils = require("./validation-utils-B7SXPkm7.cjs");
37
+ let node_path = require("node:path");
38
+ node_path = __toESM(node_path, 1);
39
+ let node_url = require("node:url");
6
40
  let _atscript_core = require("@atscript/core");
41
+ //#region src/plugin/manifest.ts
42
+ const DB_ENTITY_ANNOTATIONS = [
43
+ "db.table",
44
+ "db.view",
45
+ "db.view.for"
46
+ ];
47
+ function isDbEntity(node) {
48
+ return DB_ENTITY_ANNOTATIONS.some((name) => node.countAnnotations(name) > 0);
49
+ }
50
+ /**
51
+ * Renders the model-manifest module: an inventory of every exported
52
+ * `@db.table` / `@db.view` entity in the project, grouped by `@db.space`.
53
+ *
54
+ * The manifest is an inventory, NOT an action — consumers pass it (filtered,
55
+ * extended with external-package models, split per space) to `syncSchema` /
56
+ * `assertExposed` themselves.
57
+ *
58
+ * Runs on full builds for the `dts` / default formats (the same gate as
59
+ * `atscript.d.ts`), so narrowed special-purpose builds (e.g. the `asc db sync`
60
+ * temp compile) never shrink a committed manifest.
61
+ */
62
+ async function generateModelManifest(options, output, format, repo) {
63
+ if (format !== "dts" && format !== _atscript_core.DEFAULT_FORMAT) return;
64
+ const manifestTarget = node_path.default.isAbsolute(options.path) ? options.path : node_path.default.join(repo.root, options.path);
65
+ const manifestDir = node_path.default.dirname(manifestTarget);
66
+ const sources = [...new Set(output.map((o) => o.source).filter(Boolean))].toSorted();
67
+ const docs = await Promise.all(sources.map((source) => repo.openDocument(source)));
68
+ const entries = [];
69
+ const usedAliases = /* @__PURE__ */ new Set();
70
+ for (const [i, doc] of docs.entries()) {
71
+ if (!doc) continue;
72
+ const source = sources[i];
73
+ const docPath = source.startsWith("file://") ? (0, node_url.fileURLToPath)(source) : source;
74
+ if (docPath === manifestTarget) continue;
75
+ let specifier = node_path.default.relative(manifestDir, docPath).split(node_path.default.sep).join("/");
76
+ if (!specifier.startsWith(".")) specifier = `./${specifier}`;
77
+ for (const [exportName, node] of [...doc.exports.entries()].toSorted(([a], [b]) => a.localeCompare(b))) {
78
+ if (!isDbEntity(node)) continue;
79
+ let alias = exportName;
80
+ for (let n = 1; usedAliases.has(alias); n++) alias = `${exportName}_${n}`;
81
+ usedAliases.add(alias);
82
+ entries.push({
83
+ alias,
84
+ exportName,
85
+ specifier,
86
+ isView: node.countAnnotations("db.view") > 0 || node.countAnnotations("db.view.for") > 0,
87
+ space: require_validation_utils.getAnnotationAlias(node, "db.space") || "default"
88
+ });
89
+ }
90
+ }
91
+ const imports = entries.map((e) => e.alias === e.exportName ? `import { ${e.exportName} } from "${e.specifier}"` : `import { ${e.exportName} as ${e.alias} } from "${e.specifier}"`);
92
+ const tables = entries.filter((e) => !e.isView).map((e) => e.alias);
93
+ const views = entries.filter((e) => e.isView).map((e) => e.alias);
94
+ const spaces = /* @__PURE__ */ new Map();
95
+ for (const e of entries) {
96
+ const group = spaces.get(e.space) ?? [];
97
+ group.push(e.alias);
98
+ spaces.set(e.space, group);
99
+ }
100
+ const spaceKeys = [...spaces.keys()].toSorted((a, b) => a === "default" ? -1 : b === "default" ? 1 : a.localeCompare(b));
101
+ const list = (items) => items.length ? `[${items.join(", ")}] as const` : "[]";
102
+ const content = [
103
+ "/* oxlint-disable */",
104
+ "/* eslint-disable */",
105
+ "/**",
106
+ " * 🪄 This file was generated by Atscript (@atscript/db model manifest)",
107
+ " * Do not edit this file!",
108
+ " *",
109
+ " * Re-generate with `npx asc -f dts`.",
110
+ " */",
111
+ ...imports,
112
+ "",
113
+ `export const dbTables = ${list(tables)}`,
114
+ `export const dbViews = ${list(views)}`,
115
+ "/** Every @db.table / @db.view model in this project. */",
116
+ `export const atscriptModels = ${list(entries.map((e) => e.alias))}`,
117
+ "/** Models grouped by @db.space (absent annotation → \"default\"). */",
118
+ "export const modelsBySpace = {",
119
+ ...spaceKeys.map((key) => ` ${JSON.stringify(key)}: ${list(spaces.get(key))},`),
120
+ "} as const",
121
+ ""
122
+ ].join("\n");
123
+ output.push({
124
+ fileName: node_path.default.basename(manifestTarget),
125
+ content,
126
+ source: "",
127
+ target: manifestTarget
128
+ });
129
+ }
130
+ //#endregion
7
131
  //#region src/plugin/annotations/agg.ts
8
132
  const dbAggAnnotations = { agg: {
9
133
  sum: new _atscript_core.AnnotationSpec({
@@ -977,6 +1101,15 @@ const dbTableAnnotations = {
977
1101
  description: "Schema/namespace name."
978
1102
  }
979
1103
  }),
1104
+ space: new _atscript_core.AnnotationSpec({
1105
+ description: "Binds the entity to a named database space (a `DbSpace` — one per physical database) for apps running more than one database at once (e.g. MongoDB + PostgreSQL). Absent means the default space.\n\nConsumed by the generated model manifest (grouping in `modelsBySpace`) and by `@TableController(Model)` token binding, which resolves the space registered under this name via `provideDbSpace(space, name)`.\n\n**Example:**\n```atscript\n@db.table \"feed_runs\"\n@db.space \"analytics\"\nexport interface FeedRun { ... }\n```\n",
1106
+ nodeType: ["interface"],
1107
+ argument: {
1108
+ name: "name",
1109
+ type: "string",
1110
+ description: "Space name (matches `provideDbSpace(space, name)`). Default: \"default\"."
1111
+ }
1112
+ }),
980
1113
  http: { path: new _atscript_core.AnnotationSpec({
981
1114
  description: "HTTP endpoint path where this table is served. Used by the UI for value-help on FK fields. Gets overwritten by the final controller prefix at runtime.\n\n**Example:**\n```atscript\n@db.table \"authors\"\n@db.http.path \"/authors\"\nexport interface Author { ... }\n```\n",
982
1115
  nodeType: ["interface"],
@@ -1306,14 +1439,19 @@ const dbViewAnnotations = { view: {
1306
1439
  } };
1307
1440
  //#endregion
1308
1441
  //#region src/plugin/index.ts
1309
- const dbPlugin = () => ({
1442
+ const dbPlugin = (options) => ({
1310
1443
  name: "db",
1444
+ async buildEnd(output, format, repo) {
1445
+ if (!options?.manifest) return;
1446
+ await generateModelManifest(typeof options.manifest === "string" ? { path: options.manifest } : options.manifest, output, format, repo);
1447
+ },
1311
1448
  config() {
1312
1449
  return {
1313
1450
  annotations: { db: {
1314
1451
  patch: dbColumnAnnotations.patch,
1315
1452
  table: dbTableAnnotations.table,
1316
1453
  schema: dbTableAnnotations.schema,
1454
+ space: dbTableAnnotations.space,
1317
1455
  index: dbIndexAnnotations.index,
1318
1456
  column: dbColumnAnnotations.column,
1319
1457
  default: dbColumnAnnotations.default,
@@ -1358,5 +1496,6 @@ const dbPlugin = () => ({
1358
1496
  }
1359
1497
  });
1360
1498
  //#endregion
1499
+ exports.__exportAll = __exportAll;
1361
1500
  exports.dbPlugin = dbPlugin;
1362
1501
  exports.default = dbPlugin;
package/dist/plugin.d.cts CHANGED
@@ -1,6 +1,25 @@
1
1
  import { TAtscriptPlugin } from "@atscript/core";
2
2
 
3
+ //#region src/plugin/manifest.d.ts
4
+ /** Options for the generated model manifest (see {@link dbPlugin}). */
5
+ interface TDbManifestOptions {
6
+ /** Output path for the generated module, relative to the project root. */
7
+ path: string;
8
+ }
9
+ //#endregion
3
10
  //#region src/plugin/index.d.ts
4
- declare const dbPlugin: () => TAtscriptPlugin;
11
+ /** Options for {@link dbPlugin}. */
12
+ interface TDbPluginOptions {
13
+ /**
14
+ * When set, full builds (`asc -f dts`) additionally emit a generated model
15
+ * manifest module at this path (relative to the project root): an inventory
16
+ * of every exported `@db.table` / `@db.view` entity —
17
+ * `dbTables` / `dbViews` / `atscriptModels` / `modelsBySpace` (grouped by
18
+ * `@db.space`). Feed it to `syncSchema(db, atscriptModels)` so newly added
19
+ * models can't be silently forgotten.
20
+ */
21
+ manifest?: string | TDbManifestOptions;
22
+ }
23
+ declare const dbPlugin: (options?: TDbPluginOptions) => TAtscriptPlugin;
5
24
  //#endregion
6
- export { dbPlugin, dbPlugin as default };
25
+ export { type TDbManifestOptions, type TDbPluginOptions, dbPlugin, dbPlugin as default };
package/dist/plugin.d.mts CHANGED
@@ -1,6 +1,25 @@
1
1
  import { TAtscriptPlugin } from "@atscript/core";
2
2
 
3
+ //#region src/plugin/manifest.d.ts
4
+ /** Options for the generated model manifest (see {@link dbPlugin}). */
5
+ interface TDbManifestOptions {
6
+ /** Output path for the generated module, relative to the project root. */
7
+ path: string;
8
+ }
9
+ //#endregion
3
10
  //#region src/plugin/index.d.ts
4
- declare const dbPlugin: () => TAtscriptPlugin;
11
+ /** Options for {@link dbPlugin}. */
12
+ interface TDbPluginOptions {
13
+ /**
14
+ * When set, full builds (`asc -f dts`) additionally emit a generated model
15
+ * manifest module at this path (relative to the project root): an inventory
16
+ * of every exported `@db.table` / `@db.view` entity —
17
+ * `dbTables` / `dbViews` / `atscriptModels` / `modelsBySpace` (grouped by
18
+ * `@db.space`). Feed it to `syncSchema(db, atscriptModels)` so newly added
19
+ * models can't be silently forgotten.
20
+ */
21
+ manifest?: string | TDbManifestOptions;
22
+ }
23
+ declare const dbPlugin: (options?: TDbPluginOptions) => TAtscriptPlugin;
5
24
  //#endregion
6
- export { dbPlugin, dbPlugin as default };
25
+ export { type TDbManifestOptions, type TDbPluginOptions, dbPlugin, dbPlugin as default };
package/dist/plugin.mjs CHANGED
@@ -1,5 +1,98 @@
1
+ import "./consts-C_-5_pFq.mjs";
1
2
  import { a as getAnnotationAlias, c as getParentStruct, d as validateExclusiveWith, f as validateFieldBaseType, i as validateRefArgument, l as getParentTypeName, n as hasAnyViewAnnotation, o as getDbTableOwner, p as validateSiblingStringField, r as validateQueryScope, s as getNavTargetTypeName, t as findFKFieldsPointingTo, u as refActionAnnotation } from "./validation-utils-MWOP1Ts4.mjs";
2
- import { AnnotationSpec, isArray, isInterface, isPrimitive, isRef, isStructure } from "@atscript/core";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { AnnotationSpec, DEFAULT_FORMAT, isArray, isInterface, isPrimitive, isRef, isStructure } from "@atscript/core";
6
+ //#region src/plugin/manifest.ts
7
+ const DB_ENTITY_ANNOTATIONS = [
8
+ "db.table",
9
+ "db.view",
10
+ "db.view.for"
11
+ ];
12
+ function isDbEntity(node) {
13
+ return DB_ENTITY_ANNOTATIONS.some((name) => node.countAnnotations(name) > 0);
14
+ }
15
+ /**
16
+ * Renders the model-manifest module: an inventory of every exported
17
+ * `@db.table` / `@db.view` entity in the project, grouped by `@db.space`.
18
+ *
19
+ * The manifest is an inventory, NOT an action — consumers pass it (filtered,
20
+ * extended with external-package models, split per space) to `syncSchema` /
21
+ * `assertExposed` themselves.
22
+ *
23
+ * Runs on full builds for the `dts` / default formats (the same gate as
24
+ * `atscript.d.ts`), so narrowed special-purpose builds (e.g. the `asc db sync`
25
+ * temp compile) never shrink a committed manifest.
26
+ */
27
+ async function generateModelManifest(options, output, format, repo) {
28
+ if (format !== "dts" && format !== DEFAULT_FORMAT) return;
29
+ const manifestTarget = path.isAbsolute(options.path) ? options.path : path.join(repo.root, options.path);
30
+ const manifestDir = path.dirname(manifestTarget);
31
+ const sources = [...new Set(output.map((o) => o.source).filter(Boolean))].toSorted();
32
+ const docs = await Promise.all(sources.map((source) => repo.openDocument(source)));
33
+ const entries = [];
34
+ const usedAliases = /* @__PURE__ */ new Set();
35
+ for (const [i, doc] of docs.entries()) {
36
+ if (!doc) continue;
37
+ const source = sources[i];
38
+ const docPath = source.startsWith("file://") ? fileURLToPath(source) : source;
39
+ if (docPath === manifestTarget) continue;
40
+ let specifier = path.relative(manifestDir, docPath).split(path.sep).join("/");
41
+ if (!specifier.startsWith(".")) specifier = `./${specifier}`;
42
+ for (const [exportName, node] of [...doc.exports.entries()].toSorted(([a], [b]) => a.localeCompare(b))) {
43
+ if (!isDbEntity(node)) continue;
44
+ let alias = exportName;
45
+ for (let n = 1; usedAliases.has(alias); n++) alias = `${exportName}_${n}`;
46
+ usedAliases.add(alias);
47
+ entries.push({
48
+ alias,
49
+ exportName,
50
+ specifier,
51
+ isView: node.countAnnotations("db.view") > 0 || node.countAnnotations("db.view.for") > 0,
52
+ space: getAnnotationAlias(node, "db.space") || "default"
53
+ });
54
+ }
55
+ }
56
+ const imports = entries.map((e) => e.alias === e.exportName ? `import { ${e.exportName} } from "${e.specifier}"` : `import { ${e.exportName} as ${e.alias} } from "${e.specifier}"`);
57
+ const tables = entries.filter((e) => !e.isView).map((e) => e.alias);
58
+ const views = entries.filter((e) => e.isView).map((e) => e.alias);
59
+ const spaces = /* @__PURE__ */ new Map();
60
+ for (const e of entries) {
61
+ const group = spaces.get(e.space) ?? [];
62
+ group.push(e.alias);
63
+ spaces.set(e.space, group);
64
+ }
65
+ const spaceKeys = [...spaces.keys()].toSorted((a, b) => a === "default" ? -1 : b === "default" ? 1 : a.localeCompare(b));
66
+ const list = (items) => items.length ? `[${items.join(", ")}] as const` : "[]";
67
+ const content = [
68
+ "/* oxlint-disable */",
69
+ "/* eslint-disable */",
70
+ "/**",
71
+ " * 🪄 This file was generated by Atscript (@atscript/db model manifest)",
72
+ " * Do not edit this file!",
73
+ " *",
74
+ " * Re-generate with `npx asc -f dts`.",
75
+ " */",
76
+ ...imports,
77
+ "",
78
+ `export const dbTables = ${list(tables)}`,
79
+ `export const dbViews = ${list(views)}`,
80
+ "/** Every @db.table / @db.view model in this project. */",
81
+ `export const atscriptModels = ${list(entries.map((e) => e.alias))}`,
82
+ "/** Models grouped by @db.space (absent annotation → \"default\"). */",
83
+ "export const modelsBySpace = {",
84
+ ...spaceKeys.map((key) => ` ${JSON.stringify(key)}: ${list(spaces.get(key))},`),
85
+ "} as const",
86
+ ""
87
+ ].join("\n");
88
+ output.push({
89
+ fileName: path.basename(manifestTarget),
90
+ content,
91
+ source: "",
92
+ target: manifestTarget
93
+ });
94
+ }
95
+ //#endregion
3
96
  //#region src/plugin/annotations/agg.ts
4
97
  const dbAggAnnotations = { agg: {
5
98
  sum: new AnnotationSpec({
@@ -973,6 +1066,15 @@ const dbTableAnnotations = {
973
1066
  description: "Schema/namespace name."
974
1067
  }
975
1068
  }),
1069
+ space: new AnnotationSpec({
1070
+ description: "Binds the entity to a named database space (a `DbSpace` — one per physical database) for apps running more than one database at once (e.g. MongoDB + PostgreSQL). Absent means the default space.\n\nConsumed by the generated model manifest (grouping in `modelsBySpace`) and by `@TableController(Model)` token binding, which resolves the space registered under this name via `provideDbSpace(space, name)`.\n\n**Example:**\n```atscript\n@db.table \"feed_runs\"\n@db.space \"analytics\"\nexport interface FeedRun { ... }\n```\n",
1071
+ nodeType: ["interface"],
1072
+ argument: {
1073
+ name: "name",
1074
+ type: "string",
1075
+ description: "Space name (matches `provideDbSpace(space, name)`). Default: \"default\"."
1076
+ }
1077
+ }),
976
1078
  http: { path: new AnnotationSpec({
977
1079
  description: "HTTP endpoint path where this table is served. Used by the UI for value-help on FK fields. Gets overwritten by the final controller prefix at runtime.\n\n**Example:**\n```atscript\n@db.table \"authors\"\n@db.http.path \"/authors\"\nexport interface Author { ... }\n```\n",
978
1080
  nodeType: ["interface"],
@@ -1302,14 +1404,19 @@ const dbViewAnnotations = { view: {
1302
1404
  } };
1303
1405
  //#endregion
1304
1406
  //#region src/plugin/index.ts
1305
- const dbPlugin = () => ({
1407
+ const dbPlugin = (options) => ({
1306
1408
  name: "db",
1409
+ async buildEnd(output, format, repo) {
1410
+ if (!options?.manifest) return;
1411
+ await generateModelManifest(typeof options.manifest === "string" ? { path: options.manifest } : options.manifest, output, format, repo);
1412
+ },
1307
1413
  config() {
1308
1414
  return {
1309
1415
  annotations: { db: {
1310
1416
  patch: dbColumnAnnotations.patch,
1311
1417
  table: dbTableAnnotations.table,
1312
1418
  schema: dbTableAnnotations.schema,
1419
+ space: dbTableAnnotations.space,
1313
1420
  index: dbIndexAnnotations.index,
1314
1421
  column: dbColumnAnnotations.column,
1315
1422
  default: dbColumnAnnotations.default,
package/dist/rel.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_relation_loader = require("./relation-loader-Desvk9Ql.cjs");
3
2
  const require_nested_writer = require("./nested-writer-DoDhl3X3.cjs");
3
+ const require_relation_loader = require("./relation-loader-BnUgJsUG.cjs");
4
4
  exports.batchInsertNestedFrom = require_nested_writer.batchInsertNestedFrom;
5
5
  exports.batchInsertNestedTo = require_nested_writer.batchInsertNestedTo;
6
6
  exports.batchInsertNestedVia = require_nested_writer.batchInsertNestedVia;
@@ -1,18 +1,6 @@
1
- //#region \0rolldown/runtime.js
2
- var __defProp = Object.defineProperty;
3
- var __exportAll = (all, no_symbols) => {
4
- let target = {};
5
- for (var name in all) __defProp(target, name, {
6
- get: all[name],
7
- enumerable: true
8
- });
9
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
- return target;
11
- };
12
- //#endregion
13
1
  const require_nested_writer = require("./nested-writer-DoDhl3X3.cjs");
14
2
  //#region src/rel/relation-loader.ts
15
- var relation_loader_exports = /* @__PURE__ */ __exportAll({
3
+ var relation_loader_exports = /* @__PURE__ */ require("./plugin.cjs").__exportAll({
16
4
  ensureSelectIncludesFields: () => ensureSelectIncludesFields,
17
5
  loadRelationsImpl: () => loadRelationsImpl
18
6
  });
package/dist/sync.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_db_view = require("./db-view-UfGVUAol.cjs");
2
+ const require_db_view = require("./db-view-DnWm-ddS.cjs");
3
3
  //#region src/schema/schema-hash.ts
4
4
  /** Extracts sorted field snapshots from a readable's field descriptors. */
5
5
  function extractFieldSnapshots(fields, typeMapper) {
@@ -1018,17 +1018,38 @@ var SchemaSync = class {
1018
1018
  for (const readable of allReadables) if (readable.renamedFrom) await this.store.deleteTableSnapshot(readable.renamedFrom);
1019
1019
  await this.store.writeTrackedList(allReadables);
1020
1020
  if (erroredNames.size === 0) await this.store.writeHash(hash);
1021
- return {
1021
+ const result = {
1022
1022
  status: "synced",
1023
1023
  schemaHash: hash,
1024
1024
  entries
1025
1025
  };
1026
+ this.reportOutcome(result, opts?.onError ?? "warn");
1027
+ return result;
1026
1028
  } finally {
1027
1029
  heartbeat.stop();
1028
1030
  await this.store.releaseLock(podId);
1029
1031
  }
1030
1032
  }
1031
1033
  /**
1034
+ * Surfaces the run outcome per the `onError` policy. Reporting must never be
1035
+ * silently lost to the NoopLogger default — when no real logger is
1036
+ * configured, warnings/errors go to `console` (a production consumer lost
1037
+ * months of failed-index errors to the silent default).
1038
+ */
1039
+ reportOutcome(result, onError) {
1040
+ if (onError === "silent" || result.entries.length === 0) return;
1041
+ const out = this.logger === require_db_view.NoopLogger ? console : this.logger;
1042
+ const counts = /* @__PURE__ */ new Map();
1043
+ for (const entry of result.entries) counts.set(entry.status, (counts.get(entry.status) ?? 0) + 1);
1044
+ const summary = [...counts.entries()].map(([status, n]) => `${n} ${status}`).join(", ");
1045
+ out.log(`[schema-sync] ${result.status}: ${summary}`);
1046
+ const errored = result.entries.filter((e) => e.hasErrors);
1047
+ if (errored.length === 0) return;
1048
+ const lines = errored.map((e) => `[schema-sync] "${e.name}" failed: ${e.errors.join("; ") || e.status}`);
1049
+ for (const line of lines) out.error(line);
1050
+ if (onError === "throw") throw new Error(`[schema-sync] ${errored.length} entr${errored.length === 1 ? "y" : "ies"} failed:\n${lines.join("\n")}`);
1051
+ }
1052
+ /**
1032
1053
  * Computes a dry-run plan showing what `run()` would do, without executing any DDL.
1033
1054
  */
1034
1055
  async plan(types, opts) {
@@ -1274,6 +1295,30 @@ var SchemaSync = class {
1274
1295
  async function syncSchema(space, types, opts) {
1275
1296
  return new SchemaSync(space).run(types, opts);
1276
1297
  }
1298
+ /**
1299
+ * Computes a dry-run plan showing what {@link syncSchema} would do, without
1300
+ * executing any DDL. Wraps {@link SchemaSync.plan}.
1301
+ *
1302
+ * The plan carries structured per-entry diffs (columns to add/rename/drop,
1303
+ * type/nullable/default changes, FK changes) plus a human-readable renderer:
1304
+ *
1305
+ * ```typescript
1306
+ * import { planSchema } from '@atscript/db/sync'
1307
+ *
1308
+ * const plan = await planSchema(db, [UsersType, PostsType])
1309
+ * if (plan.status === 'changes-needed') {
1310
+ * for (const entry of plan.entries) {
1311
+ * console.log(entry.print('plan').join('\n'))
1312
+ * }
1313
+ * }
1314
+ * ```
1315
+ *
1316
+ * Note: reading the stored baseline still requires a live DB connection (the
1317
+ * snapshot lives in the `__atscript_control` table).
1318
+ */
1319
+ async function planSchema(space, types, opts) {
1320
+ return new SchemaSync(space).plan(types, opts);
1321
+ }
1277
1322
  //#endregion
1278
1323
  exports.SchemaSync = SchemaSync;
1279
1324
  exports.SyncEntry = SyncEntry;
@@ -1286,6 +1331,7 @@ exports.computeTableSnapshot = computeTableSnapshot;
1286
1331
  exports.computeViewSnapshot = computeViewSnapshot;
1287
1332
  exports.fkKey = fkKey;
1288
1333
  exports.hasForeignKeyChanges = hasForeignKeyChanges;
1334
+ exports.planSchema = planSchema;
1289
1335
  exports.readStoredSnapshot = readStoredSnapshot;
1290
1336
  exports.snapshotToExistingColumns = snapshotToExistingColumns;
1291
1337
  exports.snapshotToExistingTableOptions = snapshotToExistingTableOptions;
package/dist/sync.d.cts CHANGED
@@ -240,6 +240,16 @@ interface TSyncOptions {
240
240
  * not thrown). Default: NoopLogger — pass `console` to surface them.
241
241
  */
242
242
  logger?: TGenericLogger;
243
+ /**
244
+ * What to do when the run finishes with errored entries (failed index/FK
245
+ * DDL, external-view checks, …):
246
+ * - `"warn"` (default) — emit a one-line summary plus per-entry error lines
247
+ * via the configured logger, **falling back to `console` when no logger
248
+ * is set** (errors are never silently swallowed by the NoopLogger default);
249
+ * - `"throw"` — same reporting, then throw after snapshots/locks are handled;
250
+ * - `"silent"` — legacy behavior: outcome is only observable on the result.
251
+ */
252
+ onError?: "throw" | "warn" | "silent";
243
253
  }
244
254
  interface TSyncResult {
245
255
  status: "up-to-date" | "synced" | "synced-by-peer";
@@ -278,6 +288,13 @@ declare class SchemaSync {
278
288
  * Runs schema synchronization with distributed locking.
279
289
  */
280
290
  run(types: TAtscriptAnnotatedType[], opts?: TSyncOptions): Promise<TSyncResult>;
291
+ /**
292
+ * Surfaces the run outcome per the `onError` policy. Reporting must never be
293
+ * silently lost to the NoopLogger default — when no real logger is
294
+ * configured, warnings/errors go to `console` (a production consumer lost
295
+ * months of failed-index errors to the silent default).
296
+ */
297
+ private reportOutcome;
281
298
  /**
282
299
  * Computes a dry-run plan showing what `run()` would do, without executing any DDL.
283
300
  */
@@ -372,5 +389,27 @@ declare function hasForeignKeyChanges(diff: TForeignKeyDiff): boolean;
372
389
  * @param opts - Lock TTL, wait timeout, force mode, etc.
373
390
  */
374
391
  declare function syncSchema(space: DbSpace, types: TAtscriptAnnotatedType[], opts?: TSyncOptions): Promise<TSyncResult>;
392
+ /**
393
+ * Computes a dry-run plan showing what {@link syncSchema} would do, without
394
+ * executing any DDL. Wraps {@link SchemaSync.plan}.
395
+ *
396
+ * The plan carries structured per-entry diffs (columns to add/rename/drop,
397
+ * type/nullable/default changes, FK changes) plus a human-readable renderer:
398
+ *
399
+ * ```typescript
400
+ * import { planSchema } from '@atscript/db/sync'
401
+ *
402
+ * const plan = await planSchema(db, [UsersType, PostsType])
403
+ * if (plan.status === 'changes-needed') {
404
+ * for (const entry of plan.entries) {
405
+ * console.log(entry.print('plan').join('\n'))
406
+ * }
407
+ * }
408
+ * ```
409
+ *
410
+ * Note: reading the stored baseline still requires a live DB connection (the
411
+ * snapshot lives in the `__atscript_control` table).
412
+ */
413
+ declare function planSchema(space: DbSpace, types: TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe">): Promise<TSyncPlan>;
375
414
  //#endregion
376
- export { SchemaSync, SyncEntry, type TFieldSnapshot, type TForeignKeyDiff, type TForeignKeySnapshot, type TSyncColors, type TSyncEntryStatus, type TSyncOptions, type TSyncPlan, type TSyncResult, type TTableSnapshot, type TViewSnapshot, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema };
415
+ export { SchemaSync, SyncEntry, type TFieldSnapshot, type TForeignKeyDiff, type TForeignKeySnapshot, type TSyncColors, type TSyncEntryStatus, type TSyncOptions, type TSyncPlan, type TSyncResult, type TTableSnapshot, type TViewSnapshot, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, planSchema, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema };
package/dist/sync.d.mts CHANGED
@@ -240,6 +240,16 @@ interface TSyncOptions {
240
240
  * not thrown). Default: NoopLogger — pass `console` to surface them.
241
241
  */
242
242
  logger?: TGenericLogger;
243
+ /**
244
+ * What to do when the run finishes with errored entries (failed index/FK
245
+ * DDL, external-view checks, …):
246
+ * - `"warn"` (default) — emit a one-line summary plus per-entry error lines
247
+ * via the configured logger, **falling back to `console` when no logger
248
+ * is set** (errors are never silently swallowed by the NoopLogger default);
249
+ * - `"throw"` — same reporting, then throw after snapshots/locks are handled;
250
+ * - `"silent"` — legacy behavior: outcome is only observable on the result.
251
+ */
252
+ onError?: "throw" | "warn" | "silent";
243
253
  }
244
254
  interface TSyncResult {
245
255
  status: "up-to-date" | "synced" | "synced-by-peer";
@@ -278,6 +288,13 @@ declare class SchemaSync {
278
288
  * Runs schema synchronization with distributed locking.
279
289
  */
280
290
  run(types: TAtscriptAnnotatedType[], opts?: TSyncOptions): Promise<TSyncResult>;
291
+ /**
292
+ * Surfaces the run outcome per the `onError` policy. Reporting must never be
293
+ * silently lost to the NoopLogger default — when no real logger is
294
+ * configured, warnings/errors go to `console` (a production consumer lost
295
+ * months of failed-index errors to the silent default).
296
+ */
297
+ private reportOutcome;
281
298
  /**
282
299
  * Computes a dry-run plan showing what `run()` would do, without executing any DDL.
283
300
  */
@@ -372,5 +389,27 @@ declare function hasForeignKeyChanges(diff: TForeignKeyDiff): boolean;
372
389
  * @param opts - Lock TTL, wait timeout, force mode, etc.
373
390
  */
374
391
  declare function syncSchema(space: DbSpace, types: TAtscriptAnnotatedType[], opts?: TSyncOptions): Promise<TSyncResult>;
392
+ /**
393
+ * Computes a dry-run plan showing what {@link syncSchema} would do, without
394
+ * executing any DDL. Wraps {@link SchemaSync.plan}.
395
+ *
396
+ * The plan carries structured per-entry diffs (columns to add/rename/drop,
397
+ * type/nullable/default changes, FK changes) plus a human-readable renderer:
398
+ *
399
+ * ```typescript
400
+ * import { planSchema } from '@atscript/db/sync'
401
+ *
402
+ * const plan = await planSchema(db, [UsersType, PostsType])
403
+ * if (plan.status === 'changes-needed') {
404
+ * for (const entry of plan.entries) {
405
+ * console.log(entry.print('plan').join('\n'))
406
+ * }
407
+ * }
408
+ * ```
409
+ *
410
+ * Note: reading the stored baseline still requires a live DB connection (the
411
+ * snapshot lives in the `__atscript_control` table).
412
+ */
413
+ declare function planSchema(space: DbSpace, types: TAtscriptAnnotatedType[], opts?: Pick<TSyncOptions, "force" | "safe">): Promise<TSyncPlan>;
375
414
  //#endregion
376
- export { SchemaSync, SyncEntry, type TFieldSnapshot, type TForeignKeyDiff, type TForeignKeySnapshot, type TSyncColors, type TSyncEntryStatus, type TSyncOptions, type TSyncPlan, type TSyncResult, type TTableSnapshot, type TViewSnapshot, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema };
415
+ export { SchemaSync, SyncEntry, type TFieldSnapshot, type TForeignKeyDiff, type TForeignKeySnapshot, type TSyncColors, type TSyncEntryStatus, type TSyncOptions, type TSyncPlan, type TSyncResult, type TTableSnapshot, type TViewSnapshot, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, planSchema, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema };
package/dist/sync.mjs CHANGED
@@ -1017,17 +1017,38 @@ var SchemaSync = class {
1017
1017
  for (const readable of allReadables) if (readable.renamedFrom) await this.store.deleteTableSnapshot(readable.renamedFrom);
1018
1018
  await this.store.writeTrackedList(allReadables);
1019
1019
  if (erroredNames.size === 0) await this.store.writeHash(hash);
1020
- return {
1020
+ const result = {
1021
1021
  status: "synced",
1022
1022
  schemaHash: hash,
1023
1023
  entries
1024
1024
  };
1025
+ this.reportOutcome(result, opts?.onError ?? "warn");
1026
+ return result;
1025
1027
  } finally {
1026
1028
  heartbeat.stop();
1027
1029
  await this.store.releaseLock(podId);
1028
1030
  }
1029
1031
  }
1030
1032
  /**
1033
+ * Surfaces the run outcome per the `onError` policy. Reporting must never be
1034
+ * silently lost to the NoopLogger default — when no real logger is
1035
+ * configured, warnings/errors go to `console` (a production consumer lost
1036
+ * months of failed-index errors to the silent default).
1037
+ */
1038
+ reportOutcome(result, onError) {
1039
+ if (onError === "silent" || result.entries.length === 0) return;
1040
+ const out = this.logger === NoopLogger ? console : this.logger;
1041
+ const counts = /* @__PURE__ */ new Map();
1042
+ for (const entry of result.entries) counts.set(entry.status, (counts.get(entry.status) ?? 0) + 1);
1043
+ const summary = [...counts.entries()].map(([status, n]) => `${n} ${status}`).join(", ");
1044
+ out.log(`[schema-sync] ${result.status}: ${summary}`);
1045
+ const errored = result.entries.filter((e) => e.hasErrors);
1046
+ if (errored.length === 0) return;
1047
+ const lines = errored.map((e) => `[schema-sync] "${e.name}" failed: ${e.errors.join("; ") || e.status}`);
1048
+ for (const line of lines) out.error(line);
1049
+ if (onError === "throw") throw new Error(`[schema-sync] ${errored.length} entr${errored.length === 1 ? "y" : "ies"} failed:\n${lines.join("\n")}`);
1050
+ }
1051
+ /**
1031
1052
  * Computes a dry-run plan showing what `run()` would do, without executing any DDL.
1032
1053
  */
1033
1054
  async plan(types, opts) {
@@ -1273,5 +1294,29 @@ var SchemaSync = class {
1273
1294
  async function syncSchema(space, types, opts) {
1274
1295
  return new SchemaSync(space).run(types, opts);
1275
1296
  }
1297
+ /**
1298
+ * Computes a dry-run plan showing what {@link syncSchema} would do, without
1299
+ * executing any DDL. Wraps {@link SchemaSync.plan}.
1300
+ *
1301
+ * The plan carries structured per-entry diffs (columns to add/rename/drop,
1302
+ * type/nullable/default changes, FK changes) plus a human-readable renderer:
1303
+ *
1304
+ * ```typescript
1305
+ * import { planSchema } from '@atscript/db/sync'
1306
+ *
1307
+ * const plan = await planSchema(db, [UsersType, PostsType])
1308
+ * if (plan.status === 'changes-needed') {
1309
+ * for (const entry of plan.entries) {
1310
+ * console.log(entry.print('plan').join('\n'))
1311
+ * }
1312
+ * }
1313
+ * ```
1314
+ *
1315
+ * Note: reading the stored baseline still requires a live DB connection (the
1316
+ * snapshot lives in the `__atscript_control` table).
1317
+ */
1318
+ async function planSchema(space, types, opts) {
1319
+ return new SchemaSync(space).plan(types, opts);
1320
+ }
1276
1321
  //#endregion
1277
- export { SchemaSync, SyncEntry, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema };
1322
+ export { SchemaSync, SyncEntry, computeColumnDiff, computeForeignKeyDiff, computeSchemaHash, computeTableHash, computeTableOptionDiff, computeTableSnapshot, computeViewSnapshot, fkKey, hasForeignKeyChanges, planSchema, readStoredSnapshot, snapshotToExistingColumns, snapshotToExistingTableOptions, syncSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db",
3
- "version": "0.1.115",
3
+ "version": "0.1.117",
4
4
  "description": "Database adapter utilities for atscript.",
5
5
  "keywords": [
6
6
  "atscript",
@@ -71,14 +71,14 @@
71
71
  "access": "public"
72
72
  },
73
73
  "devDependencies": {
74
- "@atscript/core": "^0.1.82",
75
- "@atscript/typescript": "^0.1.82",
74
+ "@atscript/core": "^0.1.84",
75
+ "@atscript/typescript": "^0.1.84",
76
76
  "@uniqu/core": "^0.1.7",
77
- "unplugin-atscript": "^0.1.82"
77
+ "unplugin-atscript": "^0.1.84"
78
78
  },
79
79
  "peerDependencies": {
80
- "@atscript/core": "^0.1.82",
81
- "@atscript/typescript": "^0.1.82",
80
+ "@atscript/core": "^0.1.84",
81
+ "@atscript/typescript": "^0.1.84",
82
82
  "@uniqu/core": "^0.1.7"
83
83
  },
84
84
  "scripts": {