@ghentcdh/crouton-api 0.0.1-alpha.60 → 0.0.1-alpha.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -70,7 +70,7 @@ __export(index_exports, {
70
70
  });
71
71
  module.exports = __toCommonJS(index_exports);
72
72
 
73
- // ../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.8_@types+node@26.4.0__@swc+core@1.16.1_@swc+he_53e7170f1cd8909962d4b3404cf3712f/node_modules/tsup/assets/cjs_shims.js
73
+ // ../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.8_@types+node@26.4.0__@swc+core@1.16.1_@swc+he_9a17c50ee76d0369ad0c28a18d209a0d/node_modules/tsup/assets/cjs_shims.js
74
74
  var getImportMetaUrl = /* @__PURE__ */ __name(() => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href, "getImportMetaUrl");
75
75
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
76
76
 
@@ -98,7 +98,8 @@ var RequestSchema = import_zod2.z.object({
98
98
  sort: import_zod2.z.string().optional().default("id"),
99
99
  sortDir: SortDirEnum.optional().default("asc"),
100
100
  // Filter is of the format key:value:operator (e.g. name:john:eq) operator is optional
101
- filter: StringOrArray().optional().default([])
101
+ filter: StringOrArray().optional().default([]),
102
+ q: import_zod2.z.string().optional()
102
103
  });
103
104
  var RequestSchemaWithOffset = RequestSchema.transform((schema) => {
104
105
  const { page, pageSize, sort } = schema;
@@ -773,7 +774,7 @@ var FieldInputSchema = import_zod9.z.object({
773
774
  * Supports dynamic default tokens evaluated at form-open time:
774
775
  * - `"$now"` — current datetime ISO string
775
776
  * - `"$today"` — current date ISO string (date only, e.g. `"2025-03-14"`)
776
- * - `"$user.id"` — current user id (requires `user` on `CroutonPlugin` config)
777
+ * - `"$user"` — current user object (requires `defaults: { '$user': ... }` on `CroutonPlugin` config, or `useCrouton().setDefault('$user', ...)`)
777
778
  */
778
779
  defaultValue: import_zod9.z.unknown().optional(),
779
780
  options: import_zod9.z.union([
@@ -2846,7 +2847,7 @@ var resolveLanguage = /* @__PURE__ */ __name((acceptLanguage, supported, default
2846
2847
  }, "resolveLanguage");
2847
2848
 
2848
2849
  // src/lib/crouton-api.module.ts
2849
- var import_common26 = require("@nestjs/common");
2850
+ var import_common27 = require("@nestjs/common");
2850
2851
  var import_core2 = require("@nestjs/core");
2851
2852
 
2852
2853
  // src/lib/crud/app-layout/app-layout.types.ts
@@ -3172,6 +3173,28 @@ var patchViewTitles = /* @__PURE__ */ __name((views, columnLabels) => {
3172
3173
  } : vc;
3173
3174
  });
3174
3175
  }
3176
+ const patchUiElements = /* @__PURE__ */ __name((elements) => {
3177
+ for (const el of elements) {
3178
+ if (!el || typeof el !== "object") continue;
3179
+ const element = el;
3180
+ const scope = element.scope;
3181
+ if (scope) {
3182
+ const match = /^#\/properties\/([^/]+)/.exec(scope);
3183
+ if (match) {
3184
+ const translated = columnLabels.get(match[1]);
3185
+ if (translated) {
3186
+ const opts = element.options;
3187
+ if (opts && typeof opts === "object") opts.label = translated;
3188
+ }
3189
+ }
3190
+ }
3191
+ const nested = element.elements;
3192
+ if (Array.isArray(nested)) patchUiElements(nested);
3193
+ }
3194
+ }, "patchUiElements");
3195
+ const uiSchema = patchedView.ui_schema;
3196
+ const uiElements = uiSchema?.elements;
3197
+ if (Array.isArray(uiElements)) patchUiElements(uiElements);
3175
3198
  patched[viewName] = patchedView;
3176
3199
  }
3177
3200
  return patched;
@@ -4373,8 +4396,16 @@ var ReadRepository = class {
4373
4396
  const subResources = this.config.subResources ?? [];
4374
4397
  const projection = this.projection("findAll");
4375
4398
  const vlCols = await resolveValueLabelColumns(this.config.route, this.config.valueLabelColumns, this.configRegistry);
4399
+ const filterWhere = this.buildWhere(params.filter);
4400
+ const searchWhere = this.buildSearchOrWhere(params.q);
4401
+ const where = filterWhere && searchWhere ? {
4402
+ AND: [
4403
+ filterWhere,
4404
+ searchWhere
4405
+ ]
4406
+ } : filterWhere ?? searchWhere;
4376
4407
  const query = {
4377
- where: this.buildWhere(params.filter),
4408
+ where,
4378
4409
  take: params.pageSize,
4379
4410
  skip: offsetOf(params),
4380
4411
  orderBy: this.safeSort(sanitizeValueLabelSort(params.sort, vlCols), params.sortDir)
@@ -4432,10 +4463,30 @@ var ReadRepository = class {
4432
4463
  const withCalc = await mergeCalculatedColumnsForRows(mapped, this.config.calculatedColumns ?? [], this.tableName, this.prisma, this.config.idField ?? "id");
4433
4464
  return withCalc;
4434
4465
  }
4435
- /** Count records matching the given filter strings. */
4436
- count(filter) {
4466
+ buildSearchOrWhere(q) {
4467
+ const lookup = this.config.lookup;
4468
+ const labels = lookup?.labels?.length ? lookup.labels : lookup?.label ? [
4469
+ lookup.label
4470
+ ] : void 0;
4471
+ if (!q || !labels?.length) return void 0;
4472
+ return {
4473
+ OR: labels.map((path) => buildNestedPath(path.split("."), {
4474
+ contains: q
4475
+ }))
4476
+ };
4477
+ }
4478
+ /** Count records matching the given filter strings and optional free-text search. */
4479
+ count(filter, q) {
4480
+ const filterWhere = this.buildWhere(filter);
4481
+ const searchWhere = this.buildSearchOrWhere(q);
4482
+ const where = filterWhere && searchWhere ? {
4483
+ AND: [
4484
+ filterWhere,
4485
+ searchWhere
4486
+ ]
4487
+ } : filterWhere ?? searchWhere;
4437
4488
  return this.prismaModel.count({
4438
- where: this.buildWhere(filter)
4489
+ where
4439
4490
  });
4440
4491
  }
4441
4492
  /**
@@ -4946,7 +4997,7 @@ var PrismaDataSourceAdapter = class {
4946
4997
  const reader = new ReadRepository(prismaModel, this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);
4947
4998
  const [data, count] = await Promise.all([
4948
4999
  reader.findAll(params, ctx.request),
4949
- reader.count(params.filter ?? [])
5000
+ reader.count(params.filter ?? [], params.q)
4950
5001
  ]);
4951
5002
  return {
4952
5003
  data,
@@ -4955,7 +5006,7 @@ var PrismaDataSourceAdapter = class {
4955
5006
  }
4956
5007
  async count(model, filter, ctx) {
4957
5008
  const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, void 0, void 0, ctx.configRegistry);
4958
- return reader.count(filter);
5009
+ return reader.count(filter, ctx.q);
4959
5010
  }
4960
5011
  async findOne(model, id, ctx) {
4961
5012
  const prismaModel = this.prismaModel(model);
@@ -5438,7 +5489,10 @@ function createCrudRepository(prisma, config, dataSources, configRegistry) {
5438
5489
  });
5439
5490
  return decorateFindAll2(data, request);
5440
5491
  }, "findAll"),
5441
- count: /* @__PURE__ */ __name((filter) => resolvedAdapter.count(adapterModelKey, filter, baseCtx), "count"),
5492
+ count: /* @__PURE__ */ __name((filter, q) => resolvedAdapter.count(adapterModelKey, filter, {
5493
+ ...baseCtx,
5494
+ q
5495
+ }), "count"),
5442
5496
  findOne: /* @__PURE__ */ __name(async (id, request) => {
5443
5497
  const row = await resolvedAdapter.findOne(adapterModelKey, id, ctx(request, "findOne", id));
5444
5498
  if (row === null || row === void 0) throw new import_common10.NotFoundException(`${config.name} with id ${id} not found`);
@@ -6172,19 +6226,10 @@ var ZodValidationPipe = class {
6172
6226
  };
6173
6227
 
6174
6228
  // src/lib/crud/operations/register-findall.ts
6175
- var _findAll = /* @__PURE__ */ __name(async (repo, params, q, lookupLabel, request) => {
6176
- const effectiveParams = {
6177
- ...params
6178
- };
6179
- if (q && lookupLabel) {
6180
- effectiveParams.filter = [
6181
- ...params.filter ?? [],
6182
- `${lookupLabel}:${q}`
6183
- ];
6184
- }
6185
- const { data, count } = repo.findAllWithCount ? await repo.findAllWithCount(effectiveParams, request) : await Promise.all([
6186
- repo.findAll(effectiveParams, request),
6187
- repo.count(effectiveParams.filter)
6229
+ var _findAll = /* @__PURE__ */ __name(async (repo, params, request) => {
6230
+ const { data, count } = repo.findAllWithCount ? await repo.findAllWithCount(params, request) : await Promise.all([
6231
+ repo.findAll(params, request),
6232
+ repo.count(params.filter ?? [], params.q)
6188
6233
  ]).then(([data2, count2]) => ({
6189
6234
  data: data2,
6190
6235
  count: count2
@@ -6223,9 +6268,8 @@ var defaultFindAll = /* @__PURE__ */ __name((ctx) => {
6223
6268
  if (!isOperationEnabled2(ctx.definition, "findAll")) return;
6224
6269
  if (isOperationExternal2(ctx.definition, "findAll")) return;
6225
6270
  const { config } = ctx;
6226
- const lookupLabel = config.lookup?.label;
6227
- const findAll = /* @__PURE__ */ __name(async function(params, q, req) {
6228
- return _findAll(this.repo, params, q, lookupLabel, req);
6271
+ const findAll = /* @__PURE__ */ __name(async function(params, req) {
6272
+ return _findAll(this.repo, params, req);
6229
6273
  }, "findAll");
6230
6274
  return {
6231
6275
  route: "",
@@ -6241,12 +6285,12 @@ var childFindAll = /* @__PURE__ */ __name((sub) => (ctx) => {
6241
6285
  if (!isOperationEnabled2(sub.operations, "findAll")) return;
6242
6286
  const { cls } = ctx;
6243
6287
  const methodName = `findAllBy_${sub.childRoute}`;
6244
- const findAll = /* @__PURE__ */ __name(async function(params, q, id, req) {
6288
+ const findAll = /* @__PURE__ */ __name(async function(params, id, req) {
6245
6289
  return findAllByParent(this.repo, id, sub.childRoute, params, req);
6246
6290
  }, "findAll");
6247
6291
  const decorators = /* @__PURE__ */ __name(() => {
6248
- (0, import_common17.Param)("id")(cls.prototype, methodName, 2);
6249
- (0, import_common17.Req)()(cls.prototype, methodName, 3);
6292
+ (0, import_common17.Param)("id")(cls.prototype, methodName, 1);
6293
+ (0, import_common17.Req)()(cls.prototype, methodName, 2);
6250
6294
  }, "decorators");
6251
6295
  return {
6252
6296
  name: sub.childRoute,
@@ -6267,8 +6311,7 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
6267
6311
  const d = desc(cls, methodName);
6268
6312
  (0, import_common17.Get)(route)(cls.prototype, methodName, d);
6269
6313
  (0, import_common17.Query)(new ZodValidationPipe(RequestDtoNoOffset.schema))(cls.prototype, methodName, 0);
6270
- (0, import_common17.Query)("q")(cls.prototype, methodName, 1);
6271
- if (!sub) (0, import_common17.Req)()(cls.prototype, methodName, 2);
6314
+ if (!sub) (0, import_common17.Req)()(cls.prototype, methodName, 1);
6272
6315
  (0, import_swagger5.ApiOperation)({
6273
6316
  summary: `List all ${name}s`
6274
6317
  })(cls.prototype, methodName, d);
@@ -6950,12 +6993,23 @@ var defaultSchemas = /* @__PURE__ */ __name((ctx) => {
6950
6993
  var childSchemas = /* @__PURE__ */ __name((sub) => (ctx) => {
6951
6994
  if (!sub.views) return null;
6952
6995
  const { config, baseUrl } = ctx;
6996
+ const { route } = config;
6953
6997
  const schemasPayload = buildSubResourceViewsPayload(config, sub, baseUrl);
6954
6998
  return {
6955
6999
  route: `${sub.childRoute}/schemas`,
6956
7000
  methodName: `getSchemas_${sub.childRoute}`,
6957
7001
  name: sub.childRoute,
6958
7002
  schemasFn: /* @__PURE__ */ __name(async function() {
7003
+ const language = getRequestLanguage();
7004
+ if (IS_DEV || language) {
7005
+ const localizedParent = await this.configRegistry.getByRoute(route, language);
7006
+ if (localizedParent) {
7007
+ const localizedSub = (localizedParent.subResources ?? []).find((s) => s.childRoute === sub.childRoute);
7008
+ if (localizedSub) {
7009
+ return buildSubResourceViewsPayload(localizedParent, localizedSub, baseUrl) ?? schemasPayload;
7010
+ }
7011
+ }
7012
+ }
6959
7013
  return schemasPayload;
6960
7014
  }, "schemasFn"),
6961
7015
  decorators: /* @__PURE__ */ __name(() => {
@@ -8839,6 +8893,38 @@ var injectEnumValues2 = /* @__PURE__ */ __name((columns, enums) => {
8839
8893
  }
8840
8894
  }, "injectEnumValues");
8841
8895
 
8896
+ // src/lib/crud/interceptors/no-cache.interceptor.ts
8897
+ var import_common25 = require("@nestjs/common");
8898
+ function _ts_decorate9(decorators, target, key, desc2) {
8899
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
8900
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
8901
+ r = Reflect.decorate(decorators, target, key, desc2);
8902
+ } else {
8903
+ for (var i = decorators.length - 1; i >= 0; i--) {
8904
+ if (d = decorators[i]) {
8905
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
8906
+ }
8907
+ }
8908
+ }
8909
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
8910
+ }
8911
+ __name(_ts_decorate9, "_ts_decorate");
8912
+ var NoCacheInterceptor = class {
8913
+ static {
8914
+ __name(this, "NoCacheInterceptor");
8915
+ }
8916
+ intercept(context, next) {
8917
+ const response = context.switchToHttp().getResponse();
8918
+ response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
8919
+ response.setHeader("Pragma", "no-cache");
8920
+ response.setHeader("Expires", "0");
8921
+ return next.handle();
8922
+ }
8923
+ };
8924
+ NoCacheInterceptor = _ts_decorate9([
8925
+ (0, import_common25.Injectable)()
8926
+ ], NoCacheInterceptor);
8927
+
8842
8928
  // src/lib/crud/builder/schema.helpers.ts
8843
8929
  var pickByColumns = /* @__PURE__ */ __name((schema, columns, filter) => {
8844
8930
  if (!schema) return void 0;
@@ -9171,7 +9257,7 @@ var fromJson = /* @__PURE__ */ __name((json, schema, hooks, dirPath, baseUrl, ac
9171
9257
  };
9172
9258
  }
9173
9259
  }
9174
- const lookup = buildLookup(enrichedColumns);
9260
+ const lookup = buildLookup(enrichedColumns, dirPath);
9175
9261
  const enrichedInclude = enrichIncludeWithSort2(json.include, enrichedColumns);
9176
9262
  const definition = buildResourceDefinitions2(schema, json.operations, enrichedColumns);
9177
9263
  return {
@@ -9228,15 +9314,26 @@ var fromJson = /* @__PURE__ */ __name((json, schema, hooks, dirPath, baseUrl, ac
9228
9314
  ...pickExtensions2(json)
9229
9315
  };
9230
9316
  }, "fromJson");
9231
- var buildLookup = /* @__PURE__ */ __name((columns) => {
9317
+ var buildLookup = /* @__PURE__ */ __name((columns, dirPath) => {
9232
9318
  if (!columns) return void 0;
9233
9319
  const keyCol = columns.find((c) => c.idField);
9234
- const labelCol = columns.find((c) => c.showInLookup) ?? columns.find((c) => c.searchable);
9235
- if (!keyCol && !labelCol) return void 0;
9320
+ const searchCols = columns.filter((c) => c.showInLookup || c.searchable);
9321
+ if (!keyCol && !searchCols.length) return void 0;
9322
+ const labels = searchCols.map((col) => {
9323
+ if (col.fieldInput?.relationType === "manyToOne" && col.fieldInput?.resource && dirPath) {
9324
+ const relationName = col.id.replace(/Id$/, "");
9325
+ const child = resolveChildResource(col.fieldInput.resource, dirPath);
9326
+ const childColumns = child ? expandExtendColumns(child.json.columns, dirPath) : void 0;
9327
+ const displayCol = childColumns?.find((c) => !c.idField && !c.hiddenInTable);
9328
+ if (displayCol) return `${relationName}.${displayCol.id}`;
9329
+ }
9330
+ return col.id;
9331
+ });
9236
9332
  return {
9237
9333
  key: keyCol?.id ?? "id",
9238
- ...labelCol && {
9239
- label: labelCol.id
9334
+ ...labels.length && {
9335
+ label: labels[0],
9336
+ labels
9240
9337
  }
9241
9338
  };
9242
9339
  }, "buildLookup");
@@ -9788,9 +9885,9 @@ var buildStatus = /* @__PURE__ */ __name(async (registry2, loadedConfigs, enumRe
9788
9885
  }, "buildStatus");
9789
9886
 
9790
9887
  // src/lib/crud/status/status.controller.ts
9791
- var import_common25 = require("@nestjs/common");
9888
+ var import_common26 = require("@nestjs/common");
9792
9889
  var import_swagger13 = require("@nestjs/swagger");
9793
- function _ts_decorate9(decorators, target, key, desc2) {
9890
+ function _ts_decorate10(decorators, target, key, desc2) {
9794
9891
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
9795
9892
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
9796
9893
  r = Reflect.decorate(decorators, target, key, desc2);
@@ -9803,7 +9900,7 @@ function _ts_decorate9(decorators, target, key, desc2) {
9803
9900
  }
9804
9901
  return c > 3 && r && Object.defineProperty(target, key, r), r;
9805
9902
  }
9806
- __name(_ts_decorate9, "_ts_decorate");
9903
+ __name(_ts_decorate10, "_ts_decorate");
9807
9904
  function _ts_metadata9(metadataKey, metadataValue) {
9808
9905
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
9809
9906
  return Reflect.metadata(metadataKey, metadataValue);
@@ -9826,8 +9923,8 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
9826
9923
  return buildStatus(this.dataSourceRegistry, configs, enumRegistry, translationRegistry);
9827
9924
  }
9828
9925
  };
9829
- _ts_decorate9([
9830
- (0, import_common25.Get)("status.json"),
9926
+ _ts_decorate10([
9927
+ (0, import_common26.Get)("status.json"),
9831
9928
  (0, import_swagger13.ApiOperation)({
9832
9929
  summary: "Crouton system status (db, resources, version)"
9833
9930
  }),
@@ -9839,8 +9936,8 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
9839
9936
  _ts_metadata9("design:paramtypes", []),
9840
9937
  _ts_metadata9("design:returntype", Promise)
9841
9938
  ], StatusController.prototype, "getStatus", null);
9842
- StatusController = _ts_decorate9([
9843
- (0, import_common25.Controller)(prefix ? `${prefix}/crouton` : "crouton"),
9939
+ StatusController = _ts_decorate10([
9940
+ (0, import_common26.Controller)(prefix ? `${prefix}/crouton` : "crouton"),
9844
9941
  (0, import_swagger13.ApiTags)("Status"),
9845
9942
  _ts_metadata9("design:type", Function),
9846
9943
  _ts_metadata9("design:paramtypes", [
@@ -9858,7 +9955,7 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
9858
9955
  // src/lib/crouton-api.module.ts
9859
9956
  var import_node_path20 = require("path");
9860
9957
  var import_node_url2 = require("url");
9861
- function _ts_decorate10(decorators, target, key, desc2) {
9958
+ function _ts_decorate11(decorators, target, key, desc2) {
9862
9959
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
9863
9960
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
9864
9961
  r = Reflect.decorate(decorators, target, key, desc2);
@@ -9871,7 +9968,7 @@ function _ts_decorate10(decorators, target, key, desc2) {
9871
9968
  }
9872
9969
  return c > 3 && r && Object.defineProperty(target, key, r), r;
9873
9970
  }
9874
- __name(_ts_decorate10, "_ts_decorate");
9971
+ __name(_ts_decorate11, "_ts_decorate");
9875
9972
  var CroutonApiModule = class _CroutonApiModule {
9876
9973
  static {
9877
9974
  __name(this, "CroutonApiModule");
@@ -9980,6 +10077,10 @@ var CroutonApiModule = class _CroutonApiModule {
9980
10077
  ResourceConfigRegistry
9981
10078
  ],
9982
10079
  providers: [
10080
+ {
10081
+ provide: import_core2.APP_INTERCEPTOR,
10082
+ useClass: NoCacheInterceptor
10083
+ },
9983
10084
  {
9984
10085
  provide: import_core2.APP_FILTER,
9985
10086
  useClass: CroutonValidationExceptionFilter
@@ -10028,8 +10129,8 @@ var CroutonApiModule = class _CroutonApiModule {
10028
10129
  return _CroutonApiModule.forResources(configs, dataSources, loader, appConfig, config);
10029
10130
  }
10030
10131
  };
10031
- CroutonApiModule = _ts_decorate10([
10032
- (0, import_common26.Module)({
10132
+ CroutonApiModule = _ts_decorate11([
10133
+ (0, import_common27.Module)({
10033
10134
  controllers: [],
10034
10135
  providers: [],
10035
10136
  exports: []