@rpcbase/db 0.31.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,19 +1,38 @@
1
- import { LoadModelCtx, loadModel, loadRbModel } from './loadModel';
1
+ import { LoadModelCtx, loadGlobalModel, loadModel } from './loadModel';
2
2
  import { ModelModules } from './registerModels';
3
+ import { DefaultGlobalRbModelName, TenantAppRbModelName } from './rbModelScopes';
3
4
  import type * as frameworkSchemas from "./models";
4
5
  type ExtractModelNamesFromSchemas<TModules> = {
5
6
  [K in keyof TModules]-?: K extends `${infer Name}Schema` ? Name : never;
6
7
  }[keyof TModules] & string;
7
8
  type FrameworkModelName = ExtractModelNamesFromSchemas<typeof frameworkSchemas>;
8
9
  type WithoutRbPrefix<TName extends string> = TName extends `RB${string}` ? never : TName;
9
- type TenantInternalRbModelName = "RBUploadSession" | "RBUploadChunk" | "RBNotification" | "RBNotificationSettings";
10
- export type TenantModelName<TModules extends ModelModules> = WithoutRbPrefix<ExtractModelNamesFromSchemas<TModules>> | WithoutRbPrefix<FrameworkModelName> | TenantInternalRbModelName;
11
- export type RbModelName = ExtractModelNamesFromSchemas<typeof frameworkSchemas> extends infer Name ? Name extends string ? Name extends `RB${string}` ? Name extends "RBRtsChange" | "RBRtsCounter" | "RBUploadSession" | "RBUploadChunk" | "RBNotification" | "RBNotificationSettings" ? never : Name : never : never : never;
12
- export type ModelsClient<TModules extends ModelModules> = {
13
- register: (modules: TModules) => void;
14
- get: (modelName: TenantModelName<TModules>, ctx: LoadModelCtx) => ReturnType<typeof loadModel>;
15
- getRb: (modelName: RbModelName, ctx: LoadModelCtx) => ReturnType<typeof loadRbModel>;
10
+ type FrameworkGlobalRbModelName = Extract<FrameworkModelName, DefaultGlobalRbModelName>;
11
+ export type TenantModelName<TTenantModules extends ModelModules> = WithoutRbPrefix<ExtractModelNamesFromSchemas<TTenantModules>> | TenantAppRbModelName;
12
+ export type GlobalModelName<TGlobalModules extends ModelModules> = FrameworkGlobalRbModelName | WithoutRbPrefix<ExtractModelNamesFromSchemas<TGlobalModules>>;
13
+ type LoadedTenantModel = Awaited<ReturnType<typeof loadModel>>;
14
+ type LoadedGlobalModel = Awaited<ReturnType<typeof loadGlobalModel>>;
15
+ type ModelsGetFn<TTenantModules extends ModelModules> = {
16
+ (modelName: TenantModelName<TTenantModules>, ctx: LoadModelCtx): ReturnType<typeof loadModel>;
17
+ <const TNames extends readonly TenantModelName<TTenantModules>[]>(modelNames: TNames, ctx: LoadModelCtx): Promise<{
18
+ [K in keyof TNames]: LoadedTenantModel;
19
+ }>;
16
20
  };
17
- export declare const createModels: <TModules extends ModelModules>(modules: TModules) => ModelsClient<TModules>;
21
+ type ModelsGetGlobalFn<TGlobalModules extends ModelModules> = {
22
+ (modelName: GlobalModelName<TGlobalModules>, ctx: LoadModelCtx): ReturnType<typeof loadGlobalModel>;
23
+ <const TNames extends readonly GlobalModelName<TGlobalModules>[]>(modelNames: TNames, ctx: LoadModelCtx): Promise<{
24
+ [K in keyof TNames]: LoadedGlobalModel;
25
+ }>;
26
+ };
27
+ export type ModelsConfig<TTenantModules extends ModelModules, TGlobalModules extends ModelModules> = {
28
+ tenant: TTenantModules;
29
+ global?: TGlobalModules;
30
+ };
31
+ export type ModelsClient<TTenantModules extends ModelModules, TGlobalModules extends ModelModules> = {
32
+ register: (modules: ModelsConfig<TTenantModules, TGlobalModules>) => void;
33
+ get: ModelsGetFn<TTenantModules>;
34
+ getGlobal: ModelsGetGlobalFn<TGlobalModules>;
35
+ };
36
+ export declare const createModels: <TTenantModules extends ModelModules, TGlobalModules extends ModelModules = Record<string, never>>(modules: ModelsConfig<TTenantModules, TGlobalModules>) => ModelsClient<TTenantModules, TGlobalModules>;
18
37
  export {};
19
38
  //# sourceMappingURL=createModels.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createModels.d.ts","sourceRoot":"","sources":["../src/createModels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,KAAK,KAAK,gBAAgB,MAAM,UAAU,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAIpD,KAAK,4BAA4B,CAAC,QAAQ,IAAI;KAC3C,CAAC,IAAI,MAAM,QAAQ,CAAC,CAAC,GAAG,CAAC,SAAS,GAAG,MAAM,IAAI,QAAQ,GAAG,IAAI,GAAG,KAAK;CACxE,CAAC,MAAM,QAAQ,CAAC,GAAG,MAAM,CAAA;AAE1B,KAAK,kBAAkB,GAAG,4BAA4B,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAE/E,KAAK,eAAe,CAAC,KAAK,SAAS,MAAM,IAAI,KAAK,SAAS,KAAK,MAAM,EAAE,GAAG,KAAK,GAAG,KAAK,CAAA;AAExF,KAAK,yBAAyB,GAC1B,iBAAiB,GACjB,eAAe,GACf,gBAAgB,GAChB,wBAAwB,CAAA;AAE5B,MAAM,MAAM,eAAe,CAAC,QAAQ,SAAS,YAAY,IACrD,eAAe,CAAC,4BAA4B,CAAC,QAAQ,CAAC,CAAC,GACvD,eAAe,CAAC,kBAAkB,CAAC,GACnC,yBAAyB,CAAA;AAE7B,MAAM,MAAM,WAAW,GAAG,4BAA4B,CAAC,OAAO,gBAAgB,CAAC,SAAS,MAAM,IAAI,GAC9F,IAAI,SAAS,MAAM,GACjB,IAAI,SAAS,KAAK,MAAM,EAAE,GACxB,IAAI,SACF,aAAa,GACb,cAAc,GACd,iBAAiB,GACjB,eAAe,GACf,gBAAgB,GAChB,wBAAwB,GACxB,KAAK,GACL,IAAI,GACN,KAAK,GACP,KAAK,GACP,KAAK,CAAA;AAET,MAAM,MAAM,YAAY,CAAC,QAAQ,SAAS,YAAY,IAAI;IACxD,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAA;IACrC,GAAG,EAAE,CAAC,SAAS,EAAE,eAAe,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,YAAY,KAAK,UAAU,CAAC,OAAO,SAAS,CAAC,CAAA;IAC9F,KAAK,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,KAAK,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;CACrF,CAAA;AAED,eAAO,MAAM,YAAY,GAAI,QAAQ,SAAS,YAAY,EAAE,SAAS,QAAQ,KAAG,YAAY,CAAC,QAAQ,CAQpG,CAAA"}
1
+ {"version":3,"file":"createModels.d.ts","sourceRoot":"","sources":["../src/createModels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare const GLOBAL_DB_SUFFIX = "-global-db";
2
+ export declare const getGlobalDbName: (env?: NodeJS.ProcessEnv) => string;
3
+ export declare const getTenantDbName: (tenantId: string, env?: NodeJS.ProcessEnv) => string;
4
+ //# sourceMappingURL=dbNames.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dbNames.d.ts","sourceRoot":"","sources":["../src/dbNames.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,gBAAgB,eAAe,CAAA;AAE5C,eAAO,MAAM,eAAe,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,MAEtE,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,EAAE,MAAK,MAAM,CAAC,UAAwB,KAAG,MAExF,CAAA"}
package/dist/index.js CHANGED
@@ -225,6 +225,7 @@ const ZRBUploadSession = z.object({
225
225
  createdAt: z.date(),
226
226
  expiresAt: z.date(),
227
227
  fileId: z.string().optional(),
228
+ isPublic: z.boolean().optional(),
228
229
  error: z.string().optional()
229
230
  });
230
231
  const RBUploadSessionSchema = new Schema(
@@ -241,6 +242,7 @@ const RBUploadSessionSchema = new Schema(
241
242
  createdAt: { type: Date, required: true, default: Date.now },
242
243
  expiresAt: { type: Date, required: true },
243
244
  fileId: { type: String, required: false },
245
+ isPublic: { type: Boolean, required: false },
244
246
  error: { type: String, required: false }
245
247
  },
246
248
  {
@@ -1140,6 +1142,20 @@ function parseMixed(required = true, def) {
1140
1142
  required
1141
1143
  };
1142
1144
  }
1145
+ const getAppName$1 = (env = process.env) => {
1146
+ const appName = env.APP_NAME?.trim();
1147
+ if (!appName) {
1148
+ throw new Error("Missing APP_NAME");
1149
+ }
1150
+ return appName;
1151
+ };
1152
+ const GLOBAL_DB_SUFFIX = "-global-db";
1153
+ const getGlobalDbName = (env = process.env) => {
1154
+ return `${getAppName$1(env)}${GLOBAL_DB_SUFFIX}`;
1155
+ };
1156
+ const getTenantDbName = (tenantId, env = process.env) => {
1157
+ return `${getAppName$1(env)}-${tenantId.trim()}-db`;
1158
+ };
1143
1159
  const getMongoUrl = (env = process.env) => {
1144
1160
  const explicitUrl = env.MONGODB_URL ?? env.MONGO_URL ?? env.MONGODB_URI ?? env.DB_URL;
1145
1161
  if (explicitUrl && explicitUrl.trim()) {
@@ -1174,6 +1190,11 @@ const ensureMongooseConnection = async (dbName) => {
1174
1190
  }
1175
1191
  return connections[dbName];
1176
1192
  };
1193
+ const DEFAULT_GLOBAL_RB_MODEL_NAMES = [
1194
+ "RBUser",
1195
+ "RBTenant"
1196
+ ];
1197
+ const DEFAULT_GLOBAL_RB_MODEL_NAMES_SET = new Set(DEFAULT_GLOBAL_RB_MODEL_NAMES);
1177
1198
  const RTS_COUNTER_ID = "rts";
1178
1199
  const EXCLUDED_MODEL_NAMES = /* @__PURE__ */ new Set(["RBRtsChange", "RBRtsCounter"]);
1179
1200
  const maxDeleteIdsRaw = process.env.RB_RTS_DELETE_LOG_MAX_IDS ?? "";
@@ -1196,7 +1217,7 @@ const getDbName = (db) => {
1196
1217
  const raw = maybe.name ?? maybe.db?.databaseName;
1197
1218
  return typeof raw === "string" ? raw : "";
1198
1219
  };
1199
- const isUsersDb = (db) => getDbName(db).endsWith("-users-db");
1220
+ const isGlobalDb = (db) => getDbName(db).endsWith(GLOBAL_DB_SUFFIX);
1200
1221
  const getRtsModels = (db) => {
1201
1222
  const RtsCounter = db.models.RBRtsCounter ?? db.model("RBRtsCounter", RBRtsCounterSchema);
1202
1223
  const RtsChange = db.models.RBRtsChange ?? db.model("RBRtsChange", RBRtsChangeSchema);
@@ -1243,7 +1264,7 @@ const recordResetModel = async (db, modelName) => {
1243
1264
  const captureDeleteMeta = async (query, mode) => {
1244
1265
  const modelName = String(query?.model?.modelName ?? "");
1245
1266
  if (!modelName || modelName.startsWith("RB") || EXCLUDED_MODEL_NAMES.has(modelName)) return;
1246
- if (isUsersDb(query?.model?.db)) return;
1267
+ if (isGlobalDb(query?.model?.db)) return;
1247
1268
  const filter = typeof query.getFilter === "function" ? query.getFilter() : query.getQuery?.() ?? {};
1248
1269
  const findQuery = query.model.find(filter, { _id: 1 }).lean();
1249
1270
  if (mode === "one") {
@@ -1296,7 +1317,7 @@ const rtsChangeLogPlugin = (schema) => {
1296
1317
  if (!modelName || modelName.startsWith("RB") || EXCLUDED_MODEL_NAMES.has(modelName)) return;
1297
1318
  const db = this?.model?.db;
1298
1319
  if (!db) return;
1299
- if (isUsersDb(db)) return;
1320
+ if (isGlobalDb(db)) return;
1300
1321
  const docId = normalizeId(doc?._id);
1301
1322
  if (!docId) return;
1302
1323
  try {
@@ -1854,12 +1875,8 @@ const mongoPaginationPlugin = (schema, pluginOptions) => {
1854
1875
  return await paginateMongoQuery(this, spec, { cursor });
1855
1876
  };
1856
1877
  };
1857
- const rtsChangeLogApplied = /* @__PURE__ */ new WeakSet();
1858
- const accessibleRecordsApplied = /* @__PURE__ */ new WeakSet();
1859
- const aclPluginApplied = /* @__PURE__ */ new WeakSet();
1860
- const paginationPluginApplied = /* @__PURE__ */ new WeakSet();
1861
1878
  let cachedModels = null;
1862
- const isRtsChangelogExcludedModelName = (name) => name.startsWith("RB");
1879
+ const isRbModelName = (name) => name.startsWith("RB");
1863
1880
  const assertSchema = (exportName, value) => {
1864
1881
  if (value instanceof mongoose.Schema) return value;
1865
1882
  throw new Error(
@@ -1870,104 +1887,89 @@ const assertSchema = (exportName, value) => {
1870
1887
  ].join(" ")
1871
1888
  );
1872
1889
  };
1873
- const buildAppModels = (modules) => Object.entries(modules).filter(([key]) => key.endsWith("Schema")).map(([key, schemaValue]) => {
1890
+ const applyTenantPlugins = (schema, modelName) => {
1891
+ schema.plugin(accessibleRecordsPlugin);
1892
+ schema.plugin(mongooseAclPlugin);
1893
+ schema.plugin(mongoPaginationPlugin);
1894
+ if (!isRbModelName(modelName)) {
1895
+ schema.plugin(rtsChangeLogPlugin);
1896
+ }
1897
+ };
1898
+ const registerSchema = (target, other, modelName, schema, scope) => {
1899
+ if (target[modelName] || other[modelName]) {
1900
+ throw new Error(`Duplicate model name "${modelName}" across tenant/global scopes`);
1901
+ }
1902
+ target[modelName] = schema;
1903
+ };
1904
+ const buildSchemasFromModules = (modules) => Object.entries(modules).filter(([key]) => key.endsWith("Schema")).map(([key, schemaValue]) => {
1874
1905
  const schema = assertSchema(key, schemaValue);
1875
- const name = key.replace(/Schema$/, "");
1876
- if (!accessibleRecordsApplied.has(schema)) {
1877
- schema.plugin(accessibleRecordsPlugin);
1878
- accessibleRecordsApplied.add(schema);
1879
- }
1880
- if (!aclPluginApplied.has(schema)) {
1881
- schema.plugin(mongooseAclPlugin);
1882
- aclPluginApplied.add(schema);
1883
- }
1884
- if (!paginationPluginApplied.has(schema)) {
1885
- schema.plugin(mongoPaginationPlugin);
1886
- paginationPluginApplied.add(schema);
1887
- }
1888
- if (!isRtsChangelogExcludedModelName(name)) {
1889
- if (!rtsChangeLogApplied.has(schema)) {
1890
- schema.plugin(rtsChangeLogPlugin);
1891
- rtsChangeLogApplied.add(schema);
1906
+ const modelName = key.replace(/Schema$/, "");
1907
+ return { modelName, schema };
1908
+ });
1909
+ const registerModels = ({ tenant, global }) => {
1910
+ registerPoliciesFromModules(frameworkSchemas);
1911
+ registerPoliciesFromModules(tenant);
1912
+ const tenantSchemas = {};
1913
+ const globalSchemas = {};
1914
+ for (const { modelName, schema } of buildSchemasFromModules(frameworkSchemas)) {
1915
+ if (DEFAULT_GLOBAL_RB_MODEL_NAMES_SET.has(modelName)) {
1916
+ const cloned = schema.clone();
1917
+ registerSchema(globalSchemas, tenantSchemas, modelName, cloned);
1918
+ } else {
1919
+ const cloned = schema.clone();
1920
+ applyTenantPlugins(cloned, modelName);
1921
+ registerSchema(tenantSchemas, globalSchemas, modelName, cloned);
1892
1922
  }
1893
1923
  }
1894
- return {
1895
- name,
1896
- model: mongoose.models[name] ?? mongoose.model(name, schema)
1897
- };
1898
- });
1899
- const buildFrameworkModels = () => Object.entries(frameworkSchemas).filter(([key]) => key.endsWith("Schema")).map(([key, schemaValue]) => {
1900
- const schema = assertSchema(key, schemaValue);
1901
- const name = key.replace(/Schema$/, "");
1902
- if (!accessibleRecordsApplied.has(schema)) {
1903
- schema.plugin(accessibleRecordsPlugin);
1904
- accessibleRecordsApplied.add(schema);
1905
- }
1906
- if (!aclPluginApplied.has(schema)) {
1907
- schema.plugin(mongooseAclPlugin);
1908
- aclPluginApplied.add(schema);
1909
- }
1910
- if (!paginationPluginApplied.has(schema)) {
1911
- schema.plugin(mongoPaginationPlugin);
1912
- paginationPluginApplied.add(schema);
1913
- }
1914
- if (!isRtsChangelogExcludedModelName(name)) {
1915
- if (!rtsChangeLogApplied.has(schema)) {
1916
- schema.plugin(rtsChangeLogPlugin);
1917
- rtsChangeLogApplied.add(schema);
1924
+ for (const { modelName, schema } of buildSchemasFromModules(tenant)) {
1925
+ if (isRbModelName(modelName)) {
1926
+ throw new Error(`Invalid tenant model name "${modelName}". RB* models are reserved for rpcbase.`);
1918
1927
  }
1928
+ const cloned = schema.clone();
1929
+ applyTenantPlugins(cloned, modelName);
1930
+ registerSchema(tenantSchemas, globalSchemas, modelName, cloned);
1919
1931
  }
1920
- return {
1921
- name,
1922
- model: mongoose.models[name] ?? mongoose.model(name, schema)
1923
- };
1924
- });
1925
- const buildModels = (modules) => {
1926
- const appModels = buildAppModels(modules);
1927
- const frameworkModels = buildFrameworkModels();
1928
- return [...frameworkModels, ...appModels].reduce((acc, { name, model }) => {
1929
- acc[name] = model;
1930
- return acc;
1931
- }, {});
1932
- };
1933
- const registerModels = (modules) => {
1934
- registerPoliciesFromModules(frameworkSchemas);
1935
- registerPoliciesFromModules(modules);
1936
- cachedModels = buildModels(modules);
1932
+ for (const { modelName, schema } of buildSchemasFromModules(global ?? {})) {
1933
+ if (isRbModelName(modelName)) {
1934
+ throw new Error(`Invalid global model name "${modelName}". RB* models are reserved for rpcbase.`);
1935
+ }
1936
+ const cloned = schema.clone();
1937
+ registerSchema(globalSchemas, tenantSchemas, modelName, cloned);
1938
+ }
1939
+ const allSchemas = { ...globalSchemas, ...tenantSchemas };
1940
+ for (const [modelName, schema] of Object.entries(allSchemas)) {
1941
+ if (!mongoose.models[modelName]) {
1942
+ mongoose.model(modelName, schema);
1943
+ }
1944
+ }
1945
+ cachedModels = { tenant: tenantSchemas, global: globalSchemas };
1937
1946
  };
1938
- const getRegisteredModels = () => {
1947
+ const getRegisteredModels = (scope) => {
1939
1948
  if (!cachedModels) {
1940
1949
  throw new Error("Models not registered. Call createModels(...) once at startup (or import your models module) before using loadModel.");
1941
1950
  }
1942
- return cachedModels;
1951
+ return cachedModels[scope];
1943
1952
  };
1944
- const { APP_NAME } = process.env;
1945
- const TENANT_INTERNAL_MODEL_NAMES = /* @__PURE__ */ new Set([
1946
- "RBRtsChange",
1947
- "RBRtsCounter",
1948
- "RBUploadSession",
1949
- "RBUploadChunk",
1950
- "RBNotification",
1951
- "RBNotificationSettings"
1952
- ]);
1953
1953
  const assertTenantModelName = (modelName) => {
1954
- if (TENANT_INTERNAL_MODEL_NAMES.has(modelName)) return;
1955
1954
  assert(
1956
- !modelName.startsWith("RB"),
1957
- "Invalid tenant model name. RB* models are stored in the global users DB; use loadRbModel."
1955
+ !DEFAULT_GLOBAL_RB_MODEL_NAMES_SET.has(modelName),
1956
+ 'Invalid tenant model name. "RBUser" and "RBTenant" are stored in the global DB; use loadGlobalModel (or loadRbModel for rpcbase models).'
1958
1957
  );
1959
1958
  };
1960
1959
  const assertRbModelName = (modelName) => {
1961
1960
  assert(modelName.startsWith("RB"), "Invalid RB model name. Supported: RB*");
1962
- assert(!TENANT_INTERNAL_MODEL_NAMES.has(modelName), "Invalid RB model name. Use loadModel for tenant-scoped RB* models.");
1961
+ assert(
1962
+ DEFAULT_GLOBAL_RB_MODEL_NAMES_SET.has(modelName),
1963
+ 'Invalid RB model name. Only "RBUser" and "RBTenant" are global; use loadModel for tenant-scoped RB* models.'
1964
+ );
1963
1965
  };
1964
- const loadModelFromDb = async (modelName, dbName) => {
1965
- const models = getRegisteredModels();
1966
- const model = models[modelName];
1967
- assert(model, `Model ${modelName} not registered. Available models: ${Object.keys(models).join(", ")}`);
1966
+ const loadModelFromDb = async (modelName, dbName, scope) => {
1967
+ const schemas = getRegisteredModels(scope);
1968
+ const schema = schemas[modelName];
1969
+ assert(schema, `Model ${modelName} not registered. Available models: ${Object.keys(schemas).join(", ")}`);
1968
1970
  const modelConnection = await ensureMongooseConnection(dbName);
1969
1971
  if (!modelConnection.models[modelName]) {
1970
- modelConnection.model(modelName, model.schema);
1972
+ modelConnection.model(modelName, schema);
1971
1973
  }
1972
1974
  return modelConnection.models[modelName];
1973
1975
  };
@@ -1975,20 +1977,38 @@ const loadModel = async (modelName, ctx) => {
1975
1977
  assertTenantModelName(modelName);
1976
1978
  const tenantId = ctx.req.session?.user?.currentTenantId;
1977
1979
  assert(typeof tenantId === "string" && tenantId.trim(), "Tenant ID is missing from session");
1978
- const dbName = `${APP_NAME}-${tenantId.trim()}-db`;
1979
- return loadModelFromDb(modelName, dbName);
1980
+ const dbName = getTenantDbName(tenantId);
1981
+ return loadModelFromDb(modelName, dbName, "tenant");
1982
+ };
1983
+ const loadGlobalModel = async (modelName, _ctx) => {
1984
+ if (modelName.startsWith("RB") && !DEFAULT_GLOBAL_RB_MODEL_NAMES_SET.has(modelName)) {
1985
+ throw new Error(`Invalid global model name "${modelName}". RB* models are tenant-scoped by default; use loadModel.`);
1986
+ }
1987
+ const dbName = getGlobalDbName();
1988
+ return loadModelFromDb(modelName, dbName, "global");
1980
1989
  };
1981
1990
  const loadRbModel = async (modelName, _ctx) => {
1982
1991
  assertRbModelName(modelName);
1983
- const dbName = `${APP_NAME}-users-db`;
1984
- return loadModelFromDb(modelName, dbName);
1992
+ return loadGlobalModel(modelName);
1985
1993
  };
1986
1994
  const createModels = (modules) => {
1987
1995
  registerModels(modules);
1996
+ const get = (async (modelNameOrNames, ctx) => {
1997
+ if (Array.isArray(modelNameOrNames)) {
1998
+ return Promise.all(modelNameOrNames.map((modelName) => loadModel(modelName, ctx)));
1999
+ }
2000
+ return loadModel(modelNameOrNames, ctx);
2001
+ });
2002
+ const getGlobal = (async (modelNameOrNames, ctx) => {
2003
+ if (Array.isArray(modelNameOrNames)) {
2004
+ return Promise.all(modelNameOrNames.map((modelName) => loadGlobalModel(modelName)));
2005
+ }
2006
+ return loadGlobalModel(modelNameOrNames);
2007
+ });
1988
2008
  return {
1989
2009
  register: registerModels,
1990
- get: (modelName, ctx) => loadModel(modelName, ctx),
1991
- getRb: (modelName, ctx) => loadRbModel(modelName)
2010
+ get,
2011
+ getGlobal
1992
2012
  };
1993
2013
  };
1994
2014
  const getAppName = () => {
@@ -2057,6 +2077,7 @@ export {
2057
2077
  getTenantFilesystemDbName,
2058
2078
  getTenantRolesFromSessionUser,
2059
2079
  isPaginationValidationError,
2080
+ loadGlobalModel,
2060
2081
  loadModel,
2061
2082
  loadRbModel,
2062
2083
  mongoPaginationPlugin,
@@ -9,6 +9,7 @@ type LoadModelCtx = {
9
9
  };
10
10
  };
11
11
  export declare const loadModel: (modelName: string, ctx: LoadModelCtx) => Promise<mongoose.Model<any, {}, {}, {}, any, any, any>>;
12
+ export declare const loadGlobalModel: (modelName: string, _ctx: LoadModelCtx) => Promise<mongoose.Model<any, {}, {}, {}, any, any, any>>;
12
13
  export declare const loadRbModel: (modelName: string, _ctx: LoadModelCtx) => Promise<mongoose.Model<any, {}, {}, {}, any, any, any>>;
13
14
  export type { LoadModelCtx };
14
15
  //# sourceMappingURL=loadModel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"loadModel.d.ts","sourceRoot":"","sources":["../src/loadModel.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAA;AAMpC,KAAK,YAAY,GAAG;IAClB,GAAG,EAAE;QACH,OAAO,CAAC,EAAE;YACR,IAAI,CAAC,EAAE;gBACL,eAAe,CAAC,EAAE,MAAM,CAAC;aAC1B,CAAA;SACF,GAAG,IAAI,CAAC;KACV,CAAC;CACH,CAAC;AAyCF,eAAO,MAAM,SAAS,GAAU,WAAW,MAAM,EAAE,KAAK,YAAY,4DAOnE,CAAA;AAED,eAAO,MAAM,WAAW,GAAU,WAAW,MAAM,EAAE,MAAM,YAAY,4DAItE,CAAA;AAED,YAAY,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"loadModel.d.ts","sourceRoot":"","sources":["../src/loadModel.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAA;AAQpC,KAAK,YAAY,GAAG;IAClB,GAAG,EAAE;QACH,OAAO,CAAC,EAAE;YACR,IAAI,CAAC,EAAE;gBACL,eAAe,CAAC,EAAE,MAAM,CAAC;aAC1B,CAAA;SACF,GAAG,IAAI,CAAC;KACV,CAAC;CACH,CAAC;AAmCF,eAAO,MAAM,SAAS,GAAU,WAAW,MAAM,EAAE,KAAK,YAAY,4DAOnE,CAAA;AAED,eAAO,MAAM,eAAe,GAAU,WAAW,MAAM,EAAE,MAAM,YAAY,4DAM1E,CAAA;AAED,eAAO,MAAM,WAAW,GAAU,WAAW,MAAM,EAAE,MAAM,YAAY,4DAGtE,CAAA;AAED,YAAY,EAAE,YAAY,EAAE,CAAA"}
@@ -25,6 +25,7 @@ export declare const ZRBUploadSession: z.ZodObject<{
25
25
  createdAt: z.ZodDate;
26
26
  expiresAt: z.ZodDate;
27
27
  fileId: z.ZodOptional<z.ZodString>;
28
+ isPublic: z.ZodOptional<z.ZodBoolean>;
28
29
  error: z.ZodOptional<z.ZodString>;
29
30
  }, z.core.$strip>;
30
31
  export type IRBUploadSession = z.infer<typeof ZRBUploadSession>;
@@ -1 +1 @@
1
- {"version":3,"file":"RBUploadSession.d.ts","sourceRoot":"","sources":["../../src/models/RBUploadSession.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAGvC,eAAO,MAAM,sBAAsB;;;;;EAAuD,CAAA;AAE1F,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;iBAc3B,CAAA;AAEF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAE/D,eAAO,MAAM,qBAAqB,EAAE,MAoBnC,CAAA;AAID,eAAO,MAAM,qBAAqB,EAAE,SAkBnC,CAAA"}
1
+ {"version":3,"file":"RBUploadSession.d.ts","sourceRoot":"","sources":["../../src/models/RBUploadSession.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAGvC,eAAO,MAAM,sBAAsB;;;;;EAAuD,CAAA;AAE1F,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;iBAe3B,CAAA;AAEF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAE/D,eAAO,MAAM,qBAAqB,EAAE,MAqBnC,CAAA;AAID,eAAO,MAAM,qBAAqB,EAAE,SAkBnC,CAAA"}
@@ -0,0 +1,6 @@
1
+ export declare const DEFAULT_GLOBAL_RB_MODEL_NAMES: readonly ["RBUser", "RBTenant"];
2
+ export type DefaultGlobalRbModelName = (typeof DEFAULT_GLOBAL_RB_MODEL_NAMES)[number];
3
+ export declare const DEFAULT_GLOBAL_RB_MODEL_NAMES_SET: Set<string>;
4
+ export declare const TENANT_APP_RB_MODEL_NAMES: readonly ["RBUploadSession", "RBUploadChunk", "RBNotification", "RBNotificationSettings"];
5
+ export type TenantAppRbModelName = (typeof TENANT_APP_RB_MODEL_NAMES)[number];
6
+ //# sourceMappingURL=rbModelScopes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rbModelScopes.d.ts","sourceRoot":"","sources":["../src/rbModelScopes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,6BAA6B,iCAGhC,CAAA;AAEV,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,6BAA6B,CAAC,CAAC,MAAM,CAAC,CAAA;AAErF,eAAO,MAAM,iCAAiC,aAAiD,CAAA;AAE/F,eAAO,MAAM,yBAAyB,2FAK5B,CAAA;AAEV,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAA"}
@@ -1,6 +1,11 @@
1
1
  import { default as mongoose } from '../../vite/node_modules/mongoose';
2
2
  type ModelModules = Record<string, unknown>;
3
- export declare const registerModels: (modules: ModelModules) => void;
4
- export declare const getRegisteredModels: () => Record<string, mongoose.Model<any, {}, {}, {}, any, any, any>>;
5
- export type { ModelModules };
3
+ type ModelsScope = "tenant" | "global";
4
+ type RegisteredSchemas = Record<string, mongoose.Schema>;
5
+ export declare const registerModels: ({ tenant, global }: {
6
+ tenant: ModelModules;
7
+ global?: ModelModules;
8
+ }) => void;
9
+ export declare const getRegisteredModels: (scope: ModelsScope) => RegisteredSchemas;
10
+ export type { ModelModules, ModelsScope };
6
11
  //# sourceMappingURL=registerModels.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registerModels.d.ts","sourceRoot":"","sources":["../src/registerModels.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAiB/B,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAwF3C,eAAO,MAAM,cAAc,GAAI,SAAS,YAAY,SAInD,CAAA;AAED,eAAO,MAAM,mBAAmB,sEAK/B,CAAA;AAED,YAAY,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"registerModels.d.ts","sourceRoot":"","sources":["../src/registerModels.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAW/B,KAAK,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAC3C,KAAK,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAEtC,KAAK,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;AAuDxD,eAAO,MAAM,cAAc,GAAI,oBAAoB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAA;CAAE,SA4CjG,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,OAAO,WAAW,sBAKrD,CAAA;AAED,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"rtsChangeLogPlugin.d.ts","sourceRoot":"","sources":["../src/rtsChangeLogPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAA;AAkKpC,eAAO,MAAM,kBAAkB,GAAI,QAAQ,QAAQ,CAAC,MAAM,KAAG,IAkC5D,CAAA"}
1
+ {"version":3,"file":"rtsChangeLogPlugin.d.ts","sourceRoot":"","sources":["../src/rtsChangeLogPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAA;AAmKpC,eAAO,MAAM,kBAAkB,GAAI,QAAQ,QAAQ,CAAC,MAAM,KAAG,IAkC5D,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/db",
3
- "version": "0.31.0",
3
+ "version": "0.33.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"