tempest-express-sdk 0.29.0 → 0.30.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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { z, looseBoolean, toDict, PasswordUtils } from './chunk-7T4MZJZT.js';
2
- export { PasswordUtils, VERSION, baseAppSettingsSchema, baseAppSettingsShape, baseResponseSchema, centsField, corsSettingsShape, databaseSettingsShape, looseBoolean as envBoolean, hexColorField, latitudeField, loadSettings, longitudeField, looseBoolean, nonEmptyStrField, nonNegativeFloatField, nonNegativeIntField, percentField, portField, positiveFloatField, positiveIntField, priceField, ratingField, ratioField, serverSettingsShape, slugField, toDict, z } from './chunk-7T4MZJZT.js';
1
+ import { z, looseBoolean, toDict, PasswordUtils } from './chunk-DK46733U.js';
2
+ export { PasswordUtils, VERSION, baseAppSettingsSchema, baseAppSettingsShape, baseResponseSchema, centsField, corsSettingsShape, databaseSettingsShape, looseBoolean as envBoolean, hexColorField, latitudeField, loadSettings, longitudeField, looseBoolean, nonEmptyStrField, nonNegativeFloatField, nonNegativeIntField, percentField, portField, positiveFloatField, positiveIntField, priceField, ratingField, ratioField, serverSettingsShape, slugField, toDict, z } from './chunk-DK46733U.js';
3
3
  import { AsyncLocalStorage } from 'async_hooks';
4
4
  import { Model, column, sql, BaseRepository, RecordNotFound, detectDialect, columnsOf, NodeSqliteDriver, AsyncEngine, or, and } from 'tempest-db-js';
5
5
  export { AsyncEngine, AsyncResult, AsyncSession, BaseRepository, Column, DeleteBuilder, InsertBuilder, Model, NoResultError, NodeSqliteDriver, PostgresDialect, RecordNotFound, SelectBuilder, SqliteDialect, SyncEngine, SyncSession, UpdateBuilder, and, belongsTo, column, columnsOf, createEngine, createSyncEngine, del, detectDialect, getDialect, hasMany, insert, join, loadRelations, not, or, parseDatabaseUrl, select, sql, update } from 'tempest-db-js';
@@ -8546,6 +8546,7 @@ var TaskManager = class {
8546
8546
  broker;
8547
8547
  queue;
8548
8548
  handlers = /* @__PURE__ */ new Map();
8549
+ metadata = /* @__PURE__ */ new Map();
8549
8550
  unsubscribe = null;
8550
8551
  /**
8551
8552
  * @param options - Broker and queue name.
@@ -8559,9 +8560,32 @@ var TaskManager = class {
8559
8560
  *
8560
8561
  * @param name - The task name.
8561
8562
  * @param handler - The handler invoked with the task payload.
8563
+ * @param options - Description and declared schedule, surfaced by
8564
+ * {@link TaskManager.inventory} and by the admin panel's tasks page.
8562
8565
  */
8563
- register(name, handler) {
8566
+ register(name, handler, options = {}) {
8564
8567
  this.handlers.set(name, handler);
8568
+ this.metadata.set(name, options);
8569
+ }
8570
+ /**
8571
+ * Return what this process would run, ordered by name.
8572
+ *
8573
+ * This is the **declared** side of background work — the handlers this
8574
+ * process knows about — not queue state. A broker's pending depth is not
8575
+ * something the manager can see, and a screen that implied otherwise would
8576
+ * be worse than one that says nothing.
8577
+ *
8578
+ * @returns One entry per registered task.
8579
+ */
8580
+ inventory() {
8581
+ return [...this.handlers.keys()].sort((left, right) => left.localeCompare(right)).map((name) => {
8582
+ const meta = this.metadata.get(name) ?? {};
8583
+ return {
8584
+ name,
8585
+ description: meta.description ?? null,
8586
+ schedule: meta.schedule ?? null
8587
+ };
8588
+ });
8565
8589
  }
8566
8590
  /**
8567
8591
  * Enqueue a task by name.
@@ -8595,6 +8619,180 @@ var TaskManager = class {
8595
8619
  this.unsubscribe = null;
8596
8620
  }
8597
8621
  };
8622
+ var JobStatus = {
8623
+ /** Written, not started. */
8624
+ QUEUED: "queued",
8625
+ /** A worker picked it up. */
8626
+ RUNNING: "running",
8627
+ /** Finished cleanly. */
8628
+ SUCCEEDED: "succeeded",
8629
+ /** Finished with an error. */
8630
+ FAILED: "failed",
8631
+ /** An operator stopped it before it finished. */
8632
+ CANCELLED: "cancelled"
8633
+ };
8634
+ var TERMINAL = [
8635
+ JobStatus.SUCCEEDED,
8636
+ JobStatus.FAILED,
8637
+ JobStatus.CANCELLED
8638
+ ];
8639
+ var BaseJobModel = class extends BaseModel {
8640
+ /** The task name this run belongs to. */
8641
+ name = column.varchar(128).notNull();
8642
+ /** Lifecycle state — a {@link JobStatus} value. */
8643
+ status = column.varchar(16).notNull().default(JobStatus.QUEUED);
8644
+ /** The payload the run was started with. */
8645
+ payload = column.json();
8646
+ /** Whatever the run produced, for an operator to read afterwards. */
8647
+ result = column.json();
8648
+ /** The failure message, when the run failed. */
8649
+ error = column.text();
8650
+ /** How many times the run has been attempted. */
8651
+ attempts = column.integer().notNull().default(0);
8652
+ /** When a worker picked it up. */
8653
+ startedAt = column.datetime();
8654
+ /** When it reached a terminal state. */
8655
+ finishedAt = column.datetime();
8656
+ };
8657
+ var JobStore = class {
8658
+ /**
8659
+ * @param model - The concrete {@link BaseJobModel} subclass.
8660
+ * @param session - The session rows are written on.
8661
+ */
8662
+ constructor(model, session) {
8663
+ this.model = model;
8664
+ this.repository = new BaseRepository(model, session);
8665
+ }
8666
+ model;
8667
+ repository;
8668
+ /**
8669
+ * Record a job about to run.
8670
+ *
8671
+ * @param name - The task name.
8672
+ * @param payload - The payload the run was started with.
8673
+ * @returns The created row.
8674
+ */
8675
+ async enqueue(name, payload = {}) {
8676
+ return await this.repository.create({
8677
+ name,
8678
+ status: JobStatus.QUEUED,
8679
+ payload,
8680
+ result: null,
8681
+ error: null,
8682
+ attempts: 0,
8683
+ startedAt: null,
8684
+ finishedAt: null
8685
+ });
8686
+ }
8687
+ /**
8688
+ * Mark a job as picked up, counting the attempt.
8689
+ *
8690
+ * @param id - The job id.
8691
+ * @param attempt - Which attempt this is. Default `1`.
8692
+ * @returns How many rows changed.
8693
+ */
8694
+ async start(id, attempt = 1) {
8695
+ return await this.repository.update(
8696
+ { id },
8697
+ {
8698
+ status: JobStatus.RUNNING,
8699
+ startedAt: /* @__PURE__ */ new Date(),
8700
+ attempts: attempt
8701
+ }
8702
+ );
8703
+ }
8704
+ /**
8705
+ * Mark a job as finished cleanly.
8706
+ *
8707
+ * @param id - The job id.
8708
+ * @param result - Whatever the run produced.
8709
+ * @returns How many rows changed.
8710
+ */
8711
+ async succeed(id, result = {}) {
8712
+ return await this.repository.update(
8713
+ { id },
8714
+ {
8715
+ status: JobStatus.SUCCEEDED,
8716
+ result,
8717
+ error: null,
8718
+ finishedAt: /* @__PURE__ */ new Date()
8719
+ }
8720
+ );
8721
+ }
8722
+ /**
8723
+ * Mark a job as failed.
8724
+ *
8725
+ * @param id - The job id.
8726
+ * @param error - The failure, as an `Error` or a message.
8727
+ * @returns How many rows changed.
8728
+ */
8729
+ async fail(id, error) {
8730
+ return await this.repository.update(
8731
+ { id },
8732
+ {
8733
+ status: JobStatus.FAILED,
8734
+ error: error instanceof Error ? error.message : String(error),
8735
+ finishedAt: /* @__PURE__ */ new Date()
8736
+ }
8737
+ );
8738
+ }
8739
+ /**
8740
+ * Ask a job to stop.
8741
+ *
8742
+ * A job already in a terminal state is left alone and reported as not
8743
+ * cancelled, so an operator clicking cancel on a run that just finished sees
8744
+ * the truth rather than a row rewritten under them.
8745
+ *
8746
+ * @param id - The job id.
8747
+ * @returns Whether the row moved to `cancelled`.
8748
+ */
8749
+ async cancel(id) {
8750
+ const row = await this.repository.getByIdOrNull(id);
8751
+ if (row === null || TERMINAL.includes(String(row.status))) return false;
8752
+ const changed = await this.repository.update(
8753
+ { id },
8754
+ {
8755
+ status: JobStatus.CANCELLED,
8756
+ finishedAt: /* @__PURE__ */ new Date()
8757
+ }
8758
+ );
8759
+ return changed > 0;
8760
+ }
8761
+ /**
8762
+ * Read one job row.
8763
+ *
8764
+ * @param id - The job id.
8765
+ * @returns The row, or `null`.
8766
+ */
8767
+ async get(id) {
8768
+ return await this.repository.getByIdOrNull(id);
8769
+ }
8770
+ /**
8771
+ * Read a page of jobs, newest first.
8772
+ *
8773
+ * @param filter - Page, size and optional `name` / `status` filters.
8774
+ * @returns The page plus its metadata.
8775
+ */
8776
+ async list(filter = {}) {
8777
+ const filters = {};
8778
+ if (filter.name !== void 0 && filter.name !== "") filters.name = filter.name;
8779
+ if (filter.status !== void 0) filters.status = filter.status;
8780
+ const result = await this.repository.paginate({
8781
+ page: filter.page ?? 1,
8782
+ pageSize: filter.pageSize ?? 25,
8783
+ orderBy: "createdAt",
8784
+ ascending: false,
8785
+ ...Object.keys(filters).length === 0 ? {} : { filters }
8786
+ });
8787
+ return {
8788
+ items: result.items,
8789
+ total: result.total,
8790
+ page: result.page,
8791
+ pageSize: result.pageSize,
8792
+ pages: result.pages
8793
+ };
8794
+ }
8795
+ };
8598
8796
 
8599
8797
  // src/flags/backends.ts
8600
8798
  function coerceFlag(value) {
@@ -9667,8 +9865,8 @@ function humanizeField(name) {
9667
9865
  function adminColumns(model) {
9668
9866
  return columnsOf(model);
9669
9867
  }
9670
- function widgetForColumn(column6) {
9671
- const { kind, meta } = column6.type;
9868
+ function widgetForColumn(column7) {
9869
+ const { kind, meta } = column7.type;
9672
9870
  const plain = (widget) => ({
9673
9871
  widget,
9674
9872
  step: null,
@@ -9712,11 +9910,11 @@ function widgetForColumn(column6) {
9712
9910
  return plain("text");
9713
9911
  }
9714
9912
  }
9715
- function isColumnOptional(column6) {
9716
- return !column6.flags.notNull || column6.flags.hasDefault || column6.flags.primaryKey;
9913
+ function isColumnOptional(column7) {
9914
+ return !column7.flags.notNull || column7.flags.hasDefault || column7.flags.primaryKey;
9717
9915
  }
9718
- function filterForColumn(column6) {
9719
- const { kind, meta } = column6.type;
9916
+ function filterForColumn(column7) {
9917
+ const { kind, meta } = column7.type;
9720
9918
  if (kind === "boolean") {
9721
9919
  return {
9722
9920
  kind: "select",
@@ -9740,11 +9938,11 @@ function filterForColumn(column6) {
9740
9938
  }
9741
9939
  return { kind: "text", options: [] };
9742
9940
  }
9743
- function foreignKeyTable(column6) {
9744
- return column6.reference?.table ?? null;
9941
+ function foreignKeyTable(column7) {
9942
+ return column7.reference?.table ?? null;
9745
9943
  }
9746
- function isSearchableColumn(column6) {
9747
- const { kind } = column6.type;
9944
+ function isSearchableColumn(column7) {
9945
+ const { kind } = column7.type;
9748
9946
  return kind === "varchar" || kind === "text" || kind === "char";
9749
9947
  }
9750
9948
 
@@ -10026,8 +10224,8 @@ function formatFieldValue(widget, value) {
10026
10224
  }
10027
10225
  return String(value);
10028
10226
  }
10029
- function literalDefault(column6) {
10030
- const fallback = column6.defaultValue;
10227
+ function literalDefault(column7) {
10228
+ const fallback = column7.defaultValue;
10031
10229
  if (fallback === null || fallback.kind !== "literal") return void 0;
10032
10230
  return fallback.value;
10033
10231
  }
@@ -10040,19 +10238,19 @@ function buildFormFields(admin, options = {}) {
10040
10238
  const autocompleteLabels = options.autocompleteLabels ?? {};
10041
10239
  const uploads = new Set(admin.uploadFields);
10042
10240
  return admin.editableFieldNames().flatMap((name) => {
10043
- const column6 = columns[name];
10044
- if (column6 === void 0) return [];
10241
+ const column7 = columns[name];
10242
+ if (column7 === void 0) return [];
10045
10243
  const related = foreignKeys[name];
10046
10244
  const autocompleteUrl = autocompleteUrls[name];
10047
- const spec = uploads.has(name) ? { widget: "file", step: null, options: [] } : autocompleteUrl !== void 0 ? { widget: "autocomplete", step: null, options: [] } : related === void 0 ? widgetForColumn(column6) : { widget: "select", step: null, options: related };
10048
- const raw = name in values ? values[name] : literalDefault(column6);
10245
+ const spec = uploads.has(name) ? { widget: "file", step: null, options: [] } : autocompleteUrl !== void 0 ? { widget: "autocomplete", step: null, options: [] } : related === void 0 ? widgetForColumn(column7) : { widget: "select", step: null, options: related };
10246
+ const raw = name in values ? values[name] : literalDefault(column7);
10049
10247
  return [
10050
10248
  {
10051
10249
  name,
10052
10250
  label: humanizeField(name),
10053
10251
  widget: spec.widget,
10054
10252
  value: spec.widget === "checkbox" ? "" : formatFieldValue(spec.widget, raw),
10055
- required: !isColumnOptional(column6),
10253
+ required: !isColumnOptional(column7),
10056
10254
  checked: spec.widget === "checkbox" && toBoolean(raw),
10057
10255
  step: spec.step,
10058
10256
  options: spec.options,
@@ -10069,8 +10267,8 @@ function toBoolean(value) {
10069
10267
  if (typeof value !== "string") return false;
10070
10268
  return ["true", "on", "yes", "1"].includes(value.trim().toLowerCase());
10071
10269
  }
10072
- function coerceValue(column6, widget, raw) {
10073
- const { kind, meta } = column6.type;
10270
+ function coerceValue(column7, widget, raw) {
10271
+ const { kind, meta } = column7.type;
10074
10272
  switch (widget) {
10075
10273
  case "number": {
10076
10274
  const parsed = Number(raw);
@@ -10114,10 +10312,10 @@ function parseFormBody(admin, body, options = {}) {
10114
10312
  const only = options.only === void 0 ? null : new Set(options.only);
10115
10313
  for (const name of admin.editableFieldNames()) {
10116
10314
  if (only !== null && !only.has(name)) continue;
10117
- const column6 = columns[name];
10118
- if (column6 === void 0) continue;
10315
+ const column7 = columns[name];
10316
+ if (column7 === void 0) continue;
10119
10317
  if (uploads.has(name)) continue;
10120
- const { widget } = widgetForColumn(column6);
10318
+ const { widget } = widgetForColumn(column7);
10121
10319
  if (widget === "checkbox") {
10122
10320
  data[name] = toBoolean(body[name]);
10123
10321
  continue;
@@ -10125,16 +10323,16 @@ function parseFormBody(admin, body, options = {}) {
10125
10323
  const submitted = body[name];
10126
10324
  const raw = typeof submitted === "string" ? submitted.trim() : "";
10127
10325
  if (raw === "") {
10128
- if (!isColumnOptional(column6)) {
10326
+ if (!isColumnOptional(column7)) {
10129
10327
  errors[name] = "This field is required.";
10130
10328
  continue;
10131
10329
  }
10132
- if (column6.flags.hasDefault && !(name in body)) continue;
10330
+ if (column7.flags.hasDefault && !(name in body)) continue;
10133
10331
  data[name] = null;
10134
10332
  continue;
10135
10333
  }
10136
10334
  try {
10137
- data[name] = coerceValue(column6, widget, raw);
10335
+ data[name] = coerceValue(column7, widget, raw);
10138
10336
  } catch (error) {
10139
10337
  errors[name] = error instanceof Error ? error.message : "Invalid value.";
10140
10338
  }
@@ -10152,9 +10350,9 @@ function foreignKeyFields(admin) {
10152
10350
  const columns = adminColumns(admin.model);
10153
10351
  const out = {};
10154
10352
  for (const name of admin.editableFieldNames()) {
10155
- const column6 = columns[name];
10156
- if (column6 === void 0) continue;
10157
- const table = foreignKeyTable(column6);
10353
+ const column7 = columns[name];
10354
+ if (column7 === void 0) continue;
10355
+ const table = foreignKeyTable(column7);
10158
10356
  if (table !== null) out[name] = table;
10159
10357
  }
10160
10358
  return out;
@@ -10540,7 +10738,14 @@ var AdminSite = class {
10540
10738
  };
10541
10739
 
10542
10740
  // src/admin/styles.ts
10543
- var ADMIN_CSS = `:root {
10741
+ var ADMIN_CSS_EXTRA = `
10742
+ .tempest-log-badge--succeeded { background: #dcfce7; color: #166534; }
10743
+ .tempest-log-badge--failed { background: #fee2e2; color: #991b1b; }
10744
+ .tempest-log-badge--running { background: #dbeafe; color: #1e40af; }
10745
+ .tempest-log-badge--queued { background: #f1f5f9; color: #475569; }
10746
+ .tempest-log-badge--cancelled { background: #fef3c7; color: #92400e; }
10747
+ `;
10748
+ var ADMIN_CSS_BASE = `:root {
10544
10749
  --tempest-bg: #0f172a;
10545
10750
  --tempest-bg-soft: #1e293b;
10546
10751
  --tempest-bg-row: #f8fafc;
@@ -12099,6 +12304,7 @@ a.tempest-admin-list__new:hover {
12099
12304
  }
12100
12305
  }
12101
12306
  `;
12307
+ var ADMIN_CSS = `${ADMIN_CSS_BASE}${ADMIN_CSS_EXTRA}`;
12102
12308
 
12103
12309
  // src/admin/theme.ts
12104
12310
  var FORBIDDEN_CHARS = ["<", ">", "{", "}", '"'];
@@ -12359,11 +12565,11 @@ function renderFilter(filter) {
12359
12565
  function renderListPage(context, view) {
12360
12566
  const bulk = view.bulkActions.length > 0 && context.session !== null;
12361
12567
  const checkColumn = bulk ? 1 : 0;
12362
- const headers = view.columns.map((column6) => {
12363
- const state = view.sort[column6];
12364
- if (state === void 0) return `<th>${escapeHtml(column6)}</th>`;
12568
+ const headers = view.columns.map((column7) => {
12569
+ const state = view.sort[column7];
12570
+ if (state === void 0) return `<th>${escapeHtml(column7)}</th>`;
12365
12571
  const arrow = state.active ? state.ascending ? "\u25B2" : "\u25BC" : "\u2195";
12366
- return `<th><a class="tempest-sort${state.active ? " tempest-sort--active" : ""}" href="${escapeHtml(state.url)}"><span>${escapeHtml(column6)}</span><span class="tempest-sort__arrow" aria-hidden="true">${arrow}</span></a></th>`;
12572
+ return `<th><a class="tempest-sort${state.active ? " tempest-sort--active" : ""}" href="${escapeHtml(state.url)}"><span>${escapeHtml(column7)}</span><span class="tempest-sort__arrow" aria-hidden="true">${arrow}</span></a></th>`;
12367
12573
  }).join("");
12368
12574
  const rows = view.rows.length > 0 ? view.rows.map((row) => {
12369
12575
  const check = bulk ? `<td class="tempest-admin-list__check"><input type="checkbox" name="ids" value="${escapeHtml(row.identity)}" data-row-check aria-label="Select row"></td>` : "";
@@ -12504,7 +12710,7 @@ function renderInline(inline, csrfToken, error) {
12504
12710
  if (inline.rows.length === 0) {
12505
12711
  return `<section class="tempest-admin-inline">${heading}<p><em>No related records.</em></p></section>`;
12506
12712
  }
12507
- const head2 = `<tr>${inline.columns.map((column6) => `<th>${escapeHtml(column6)}</th>`).join("")}<th></th></tr>`;
12713
+ const head2 = `<tr>${inline.columns.map((column7) => `<th>${escapeHtml(column7)}</th>`).join("")}<th></th></tr>`;
12508
12714
  const body = inline.rows.map(
12509
12715
  (row) => `<tr>${row.cells.map((cell) => `<td>${escapeHtml(cell)}</td>`).join("")}<td>${row.url === null ? "" : `<a href="${escapeHtml(row.url)}">View</a>`}</td></tr>`
12510
12716
  ).join("");
@@ -12519,7 +12725,7 @@ function renderInline(inline, csrfToken, error) {
12519
12725
  ${more}
12520
12726
  </section>`;
12521
12727
  }
12522
- const head = `<tr>${inline.columns.map((column6) => `<th>${escapeHtml(column6)}</th>`).join("")}${inline.canDelete ? "<th>Delete</th>" : ""}</tr>`;
12728
+ const head = `<tr>${inline.columns.map((column7) => `<th>${escapeHtml(column7)}</th>`).join("")}${inline.canDelete ? "<th>Delete</th>" : ""}</tr>`;
12523
12729
  const renderRow = (row, isNew) => `<tr${isNew ? ' class="tempest-admin-inline__new"' : ""}>${row.fields.map((field) => `<td>${renderInlineCell(field)}</td>`).join("")}${inline.canDelete ? `<td class="tempest-admin-inline__del">${isNew ? "" : `<input type="checkbox" name="row.${escapeHtml(row.key)}.__delete" value="true">`}</td>` : ""}</tr>`;
12524
12730
  const rows = inline.rows.map((row) => renderRow(row, false)).join("");
12525
12731
  const blank = inline.newRow === null ? "" : renderRow(inline.newRow, true);
@@ -12690,12 +12896,86 @@ function renderLogsPage(context, view) {
12690
12896
  </section>`;
12691
12897
  return renderLayout(context, `Logs \xB7 ${context.site.title}`, body);
12692
12898
  }
12899
+ function renderTasksPage(context, view) {
12900
+ const declared = view.inventory === null ? "" : `<section class="tempest-admin-tasks__declared">
12901
+ <h2>Declared</h2>
12902
+ ${view.inventory.length === 0 ? "<p><em>No tasks registered in this process.</em></p>" : `<div class="tempest-admin-table-wrap"><table class="tempest-admin-list__table">
12903
+ <thead><tr><th>Task</th><th>Schedule</th><th>Description</th></tr></thead>
12904
+ <tbody>${view.inventory.map(
12905
+ (entry) => `<tr><td>${escapeHtml(entry.name)}</td><td>${escapeHtml(entry.schedule)}</td><td>${escapeHtml(entry.description)}</td></tr>`
12906
+ ).join("")}</tbody>
12907
+ </table></div>`}
12908
+ </section>`;
12909
+ const runs = view.runs === null ? "" : `<section class="tempest-admin-tasks__runs">
12910
+ <h2>Runs</h2>
12911
+ <div class="tempest-admin-list__toolbar">
12912
+ <form method="get" class="tempest-admin-list__filters">
12913
+ <label><span>Status</span><select name="status">${view.runs.statuses.map(
12914
+ (status) => `<option value="${escapeHtml(status.value)}"${status.selected ? " selected" : ""}>${escapeHtml(status.label)}</option>`
12915
+ ).join("")}</select></label>
12916
+ <input type="search" name="task" value="${escapeHtml(view.runs.nameQuery)}" placeholder="Task name\u2026" aria-label="Task name">
12917
+ <button type="submit">Apply</button>
12918
+ </form>
12919
+ </div>
12920
+ <div class="tempest-admin-table-wrap"><table class="tempest-admin-list__table">
12921
+ <thead><tr><th>Task</th><th>Status</th><th>Started</th><th>Finished</th><th>Attempts</th><th></th></tr></thead>
12922
+ <tbody>${view.runs.rows.length === 0 ? '<tr><td colspan="6">No runs recorded yet.</td></tr>' : view.runs.rows.map(
12923
+ (row) => `<tr>
12924
+ <td>${escapeHtml(row.name)}</td>
12925
+ <td><span class="tempest-log-badge tempest-log-badge--${escapeHtml(row.status)}">${escapeHtml(row.status)}</span></td>
12926
+ <td>${escapeHtml(row.startedAt)}</td>
12927
+ <td>${escapeHtml(row.finishedAt)}</td>
12928
+ <td>${escapeHtml(row.attempts)}</td>
12929
+ <td><a href="${escapeHtml(row.url)}">View</a></td>
12930
+ </tr>`
12931
+ ).join("")}</tbody>
12932
+ </table></div>
12933
+ ${view.runs.pages > 1 ? `<nav class="tempest-admin-list__pagination" aria-label="Pagination">
12934
+ ${view.runs.prevUrl !== null ? `<a href="${escapeHtml(view.runs.prevUrl)}">\u2190 Prev</a>` : ""}
12935
+ <span>Page ${escapeHtml(view.runs.page)} of ${escapeHtml(view.runs.pages)}</span>
12936
+ ${view.runs.nextUrl !== null ? `<a href="${escapeHtml(view.runs.nextUrl)}">Next \u2192</a>` : ""}
12937
+ </nav>` : ""}
12938
+ </section>`;
12939
+ const body = `<section class="tempest-admin-tasks">
12940
+ <header class="tempest-admin-list__header">
12941
+ <h1>Tasks</h1>
12942
+ <p>What this process declares, and what its workers recorded.</p>
12943
+ </header>
12944
+ ${declared}
12945
+ ${runs}
12946
+ <p class="tempest-admin-form__hint">Live queue depth is not shown: a broker does not expose it, and a number that looked like one would be worse than none.</p>
12947
+ </section>`;
12948
+ return renderLayout(context, `Tasks \xB7 ${context.site.title}`, body);
12949
+ }
12950
+ function renderTaskDetailPage(context, view) {
12951
+ if (context.session === null) throw new Error("The task detail requires a session");
12952
+ const block = (label, content) => content === null ? "" : `<h2>${escapeHtml(label)}</h2><pre class="tempest-admin-detail__json">${escapeHtml(content)}</pre>`;
12953
+ const body = `<section class="tempest-admin-detail">
12954
+ <header class="tempest-admin-detail__header">
12955
+ <h1>${escapeHtml(view.name)} \xB7 <span class="tempest-log-badge tempest-log-badge--${escapeHtml(view.status)}">${escapeHtml(view.status)}</span></h1>
12956
+ <div class="tempest-admin-detail__actions">
12957
+ <a href="${escapeHtml(view.backUrl)}">\u2190 Back to tasks</a>
12958
+ ${view.cancelUrl !== null ? `<form method="post" action="${escapeHtml(view.cancelUrl)}" class="tempest-admin-detail__delete" onsubmit="return confirm('Ask this run to stop?');">
12959
+ <input type="hidden" name="csrf_token" value="${escapeHtml(context.session.csrfToken)}">
12960
+ <button type="submit" class="tempest-admin-btn--danger">Cancel</button>
12961
+ </form>` : ""}
12962
+ </div>
12963
+ </header>
12964
+ <dl class="tempest-admin-detail__fields">${view.fields.map(
12965
+ (field) => `<dt>${escapeHtml(field.label)}</dt><dd>${field.value === "" ? "<em>\u2014</em>" : escapeHtml(field.value)}</dd>`
12966
+ ).join("")}</dl>
12967
+ ${view.error === null ? "" : `<p class="tempest-admin-form__error">${escapeHtml(view.error)}</p>`}
12968
+ ${block("Payload", view.payload)}
12969
+ ${block("Result", view.result)}
12970
+ </section>`;
12971
+ return renderLayout(context, `${view.name} \xB7 ${context.site.title}`, body);
12972
+ }
12693
12973
  function renderSqlPage(context, view) {
12694
12974
  if (context.session === null) throw new Error("The SQL console requires a session");
12695
12975
  const result = view.rowCount === null ? "" : `<p class="tempest-admin-form__hint">${escapeHtml(view.rowCount)} row${view.rowCount === 1 ? "" : "s"}${view.durationMs === null ? "" : ` in ${escapeHtml(view.durationMs)} ms`}${view.truncated ? " (truncated by the row cap)" : ""}.</p>
12696
12976
  <div class="tempest-admin-table-wrap">
12697
12977
  <table class="tempest-admin-list__table">
12698
- <thead><tr>${view.columns.map((column6) => `<th>${escapeHtml(column6)}</th>`).join("")}</tr></thead>
12978
+ <thead><tr>${view.columns.map((column7) => `<th>${escapeHtml(column7)}</th>`).join("")}</tr></thead>
12699
12979
  <tbody>${view.rows.map(
12700
12980
  (row) => `<tr>${row.map((cell) => `<td>${escapeHtml(cell)}</td>`).join("")}</tr>`
12701
12981
  ).join("")}</tbody>
@@ -12865,6 +13145,15 @@ function makeLogsRouter(options) {
12865
13145
  return router;
12866
13146
  }
12867
13147
  var logger2 = new JSONLogger("tempest_express_sdk.admin.router");
13148
+ var JOB_STATUSES = [
13149
+ "queued",
13150
+ "running",
13151
+ "succeeded",
13152
+ "failed",
13153
+ "cancelled"
13154
+ ];
13155
+ var TERMINAL_JOB_STATUSES = ["succeeded", "failed", "cancelled"];
13156
+ var TASK_PAGE_SIZE = 25;
12868
13157
  var LOG_SOURCES = ["all", "debug", "info", "warning", "error", "500"];
12869
13158
  var LOG_PAGE_SIZE = 50;
12870
13159
  var LOG_EXPORT_MAX = 500;
@@ -12906,6 +13195,9 @@ function makeAdminRouter(site, options) {
12906
13195
  if (options.sqlConsole !== void 0) {
12907
13196
  systemNav.push({ label: "SQL console", url: `${prefix}/sql` });
12908
13197
  }
13198
+ if (options.tasks !== void 0) {
13199
+ systemNav.push({ label: "Tasks", url: `${prefix}/tasks` });
13200
+ }
12909
13201
  const maxUploadBytes = options.maxUploadBytes ?? 10 * 1024 * 1024;
12910
13202
  const sessions = new AdminSessionStore({
12911
13203
  secret: options.secretKey,
@@ -13310,7 +13602,7 @@ function makeAdminRouter(site, options) {
13310
13602
  error: null,
13311
13603
  columns,
13312
13604
  rows: window.map(
13313
- (row) => columns.map((column6) => formatCellValue(row[column6]))
13605
+ (row) => columns.map((column7) => formatCellValue(row[column7]))
13314
13606
  ),
13315
13607
  rowCount: rows.length,
13316
13608
  truncated: rows.length > window.length,
@@ -13319,6 +13611,115 @@ function makeAdminRouter(site, options) {
13319
13611
  })
13320
13612
  );
13321
13613
  }
13614
+ if (options.tasks !== void 0) {
13615
+ const tasks = options.tasks;
13616
+ router.get(
13617
+ `${prefix}/tasks`,
13618
+ guarded(async (req, res) => {
13619
+ const state = await authenticate(req, res);
13620
+ if (state === null) return;
13621
+ const inventory = tasks.manager === void 0 ? null : tasks.manager.inventory().map((entry) => ({
13622
+ name: entry.name,
13623
+ description: entry.description ?? "",
13624
+ schedule: entry.schedule ?? "\u2014"
13625
+ }));
13626
+ let runs = null;
13627
+ if (tasks.jobs !== void 0) {
13628
+ const store = tasks.jobs(state.dbSession);
13629
+ const page2 = Math.max(1, Number.parseInt(queryString(req.query.page), 10) || 1);
13630
+ const status = queryString(req.query.status);
13631
+ const name = queryString(req.query.task);
13632
+ const result = await store.list({
13633
+ page: page2,
13634
+ pageSize: TASK_PAGE_SIZE,
13635
+ ...name === "" ? {} : { name },
13636
+ ...JOB_STATUSES.includes(status) ? { status } : {}
13637
+ });
13638
+ const pageUrl = (target) => `?${buildQuery({ status, task: name, page: target })}`;
13639
+ runs = {
13640
+ rows: result.items.map((row) => ({
13641
+ id: String(row.id),
13642
+ name: String(row.name ?? ""),
13643
+ status: String(row.status ?? ""),
13644
+ startedAt: formatCellValue(row.startedAt),
13645
+ finishedAt: formatCellValue(row.finishedAt),
13646
+ attempts: formatCellValue(row.attempts),
13647
+ url: `${prefix}/tasks/${String(row.id)}`
13648
+ })),
13649
+ total: result.total,
13650
+ page: result.page,
13651
+ pages: result.pages,
13652
+ prevUrl: result.page > 1 ? pageUrl(result.page - 1) : null,
13653
+ nextUrl: result.page < result.pages ? pageUrl(result.page + 1) : null,
13654
+ statuses: ["", ...JOB_STATUSES].map((value) => ({
13655
+ value,
13656
+ label: value === "" ? "\u2014 any \u2014" : humanizeField(value),
13657
+ selected: value === status
13658
+ })),
13659
+ nameQuery: name
13660
+ };
13661
+ }
13662
+ html(
13663
+ res,
13664
+ renderTasksPage(context(req, state.session, state.visible), {
13665
+ inventory,
13666
+ runs
13667
+ })
13668
+ );
13669
+ })
13670
+ );
13671
+ if (tasks.jobs !== void 0) {
13672
+ const jobs = tasks.jobs;
13673
+ router.get(
13674
+ `${prefix}/tasks/:id`,
13675
+ guarded(async (req, res) => {
13676
+ const state = await authenticate(req, res);
13677
+ if (state === null) return;
13678
+ const row = await jobs(state.dbSession).get(String(req.params.id));
13679
+ if (row === null) {
13680
+ html(res, renderNotFound(context(req, state.session, state.visible)), 404);
13681
+ return;
13682
+ }
13683
+ const status = String(row.status ?? "");
13684
+ html(
13685
+ res,
13686
+ renderTaskDetailPage(context(req, state.session, state.visible), {
13687
+ id: String(row.id),
13688
+ name: String(row.name ?? ""),
13689
+ status,
13690
+ fields: [
13691
+ { label: "Created At", value: formatCellValue(row.createdAt) },
13692
+ { label: "Started At", value: formatCellValue(row.startedAt) },
13693
+ { label: "Finished At", value: formatCellValue(row.finishedAt) },
13694
+ { label: "Attempts", value: formatCellValue(row.attempts) }
13695
+ ],
13696
+ payload: jsonBlock(row.payload),
13697
+ result: jsonBlock(row.result),
13698
+ error: typeof row.error === "string" && row.error !== "" ? row.error : null,
13699
+ backUrl: `${prefix}/tasks`,
13700
+ cancelUrl: TERMINAL_JOB_STATUSES.includes(status) ? null : `${prefix}/tasks/${String(row.id)}/cancel`
13701
+ })
13702
+ );
13703
+ })
13704
+ );
13705
+ router.post(
13706
+ `${prefix}/tasks/:id/cancel`,
13707
+ guarded(async (req, res) => {
13708
+ const state = await authenticate(req, res);
13709
+ if (state === null) return;
13710
+ if (!checkCsrf(req, res, state)) return;
13711
+ const id = String(req.params.id);
13712
+ const cancelled = await jobs(state.dbSession).cancel(id);
13713
+ res.redirect(
13714
+ `${prefix}/tasks/${id}?${buildQuery({
13715
+ flash: cancelled ? "The run was asked to stop." : "That run had already finished.",
13716
+ level: cancelled ? "success" : "warning"
13717
+ })}`
13718
+ );
13719
+ })
13720
+ );
13721
+ }
13722
+ }
13322
13723
  router.get(
13323
13724
  `${prefix}/m/:slug`,
13324
13725
  guarded(async (req, res) => {
@@ -13629,8 +14030,8 @@ function makeAdminRouter(site, options) {
13629
14030
  res.status(404).json({ options: [] });
13630
14031
  return;
13631
14032
  }
13632
- const column6 = adminColumns(admin.model)[field];
13633
- const table = column6 === void 0 ? null : foreignKeyTable(column6);
14033
+ const column7 = adminColumns(admin.model)[field];
14034
+ const table = column7 === void 0 ? null : foreignKeyTable(column7);
13634
14035
  const referenced = table === null ? null : site.get(table);
13635
14036
  if (referenced === null) {
13636
14037
  res.json({ options: [] });
@@ -13939,7 +14340,7 @@ function makeAdminRouter(site, options) {
13939
14340
  formAction: "",
13940
14341
  rows: visible.map((child) => ({
13941
14342
  key: String(child[childAdmin?.identityField ?? "id"]),
13942
- cells: columns.map((column6) => formatCellValue(child[column6])),
14343
+ cells: columns.map((column7) => formatCellValue(child[column7])),
13943
14344
  fields: [],
13944
14345
  url: childAdmin === null ? null : `${prefix}/m/${inline.slug}/${String(child[childAdmin.identityField])}`
13945
14346
  })),
@@ -14071,8 +14472,8 @@ function makeAdminRouter(site, options) {
14071
14472
  for (const field of admin.uploadFields) {
14072
14473
  const file = files.find((candidate) => candidate.field === field);
14073
14474
  if (file === void 0) {
14074
- const column6 = columns[field];
14075
- if (creating && column6 !== void 0 && !isColumnOptional(column6)) {
14475
+ const column7 = columns[field];
14476
+ if (creating && column7 !== void 0 && !isColumnOptional(column7)) {
14076
14477
  errors[field] = "This field is required.";
14077
14478
  }
14078
14479
  continue;
@@ -14104,14 +14505,14 @@ function makeAdminRouter(site, options) {
14104
14505
  });
14105
14506
  const displayed = admin.listDisplayNames();
14106
14507
  const sort = {};
14107
- for (const column6 of displayed) {
14108
- if (!(column6 in columns)) continue;
14109
- const active = (query.sortColumn ?? admin.orderKey) === column6;
14508
+ for (const column7 of displayed) {
14509
+ if (!(column7 in columns)) continue;
14510
+ const active = (query.sortColumn ?? admin.orderKey) === column7;
14110
14511
  const nextAscending = active ? !query.ascending : true;
14111
- sort[column6] = {
14512
+ sort[column7] = {
14112
14513
  url: `?${buildQuery({
14113
14514
  ...query.baseQuery,
14114
- sort: column6,
14515
+ sort: column7,
14115
14516
  dir: nextAscending ? "asc" : "desc"
14116
14517
  })}`,
14117
14518
  active,
@@ -14132,7 +14533,7 @@ function makeAdminRouter(site, options) {
14132
14533
  const identity = String(row[admin.identityField]);
14133
14534
  return {
14134
14535
  identity,
14135
- cells: displayed.map((column6) => formatCellValue(row[column6])),
14536
+ cells: displayed.map((column7) => formatCellValue(row[column7])),
14136
14537
  url: `${prefix}/m/${admin.slug()}/${identity}`
14137
14538
  };
14138
14539
  }),
@@ -14178,9 +14579,9 @@ function makeAdminRouter(site, options) {
14178
14579
  }
14179
14580
  const filterViews = [];
14180
14581
  for (const field of admin.listFilter) {
14181
- const column6 = columns[field];
14182
- if (column6 === void 0) continue;
14183
- const spec = filterForColumn(column6);
14582
+ const column7 = columns[field];
14583
+ if (column7 === void 0) continue;
14584
+ const spec = filterForColumn(column7);
14184
14585
  if (spec.kind === "daterange") {
14185
14586
  const from = queryString(req.query[`filter_${field}_from`]);
14186
14587
  const to = queryString(req.query[`filter_${field}_to`]);
@@ -14199,12 +14600,12 @@ function makeAdminRouter(site, options) {
14199
14600
  });
14200
14601
  continue;
14201
14602
  }
14202
- const related = await relatedOptions(column6, dbSession);
14603
+ const related = await relatedOptions(column7, dbSession);
14203
14604
  const options2 = related ?? spec.options;
14204
14605
  const value = queryString(req.query[`filter_${field}`]);
14205
14606
  if (value !== "") {
14206
14607
  conditions.push({
14207
- [field]: column6.type.kind === "boolean" ? value === "true" : value
14608
+ [field]: column7.type.kind === "boolean" ? value === "true" : value
14208
14609
  });
14209
14610
  }
14210
14611
  filterViews.push({
@@ -14222,8 +14623,8 @@ function makeAdminRouter(site, options) {
14222
14623
  });
14223
14624
  }
14224
14625
  const searchable = admin.searchFields.filter((field) => {
14225
- const column6 = columns[field];
14226
- return column6 !== void 0 && isSearchableColumn(column6);
14626
+ const column7 = columns[field];
14627
+ return column7 !== void 0 && isSearchableColumn(column7);
14227
14628
  });
14228
14629
  if (search !== "" && searchable.length > 0) {
14229
14630
  conditions.push(
@@ -14256,8 +14657,8 @@ function makeAdminRouter(site, options) {
14256
14657
  lens: lens?.slug ?? ""
14257
14658
  };
14258
14659
  }
14259
- async function relatedOptions(column6, dbSession) {
14260
- const table = foreignKeyTable(column6);
14660
+ async function relatedOptions(column7, dbSession) {
14661
+ const table = foreignKeyTable(column7);
14261
14662
  if (table === null) return null;
14262
14663
  const referenced = site.get(table);
14263
14664
  if (referenced === null) return null;
@@ -14272,9 +14673,9 @@ function makeAdminRouter(site, options) {
14272
14673
  const options2 = {};
14273
14674
  for (const field of Object.keys(foreignKeyFields(admin))) {
14274
14675
  if (admin.autocompleteFields.includes(field)) continue;
14275
- const column6 = columns[field];
14276
- if (column6 === void 0) continue;
14277
- const related = await relatedOptions(column6, dbSession);
14676
+ const column7 = columns[field];
14677
+ if (column7 === void 0) continue;
14678
+ const related = await relatedOptions(column7, dbSession);
14278
14679
  if (related !== null) options2[field] = related;
14279
14680
  }
14280
14681
  return options2;
@@ -14293,8 +14694,8 @@ function makeAdminRouter(site, options) {
14293
14694
  for (const field of admin.autocompleteFields) {
14294
14695
  const value = row[field];
14295
14696
  if (value === null || value === void 0 || value === "") continue;
14296
- const column6 = columns[field];
14297
- const table = column6 === void 0 ? null : foreignKeyTable(column6);
14697
+ const column7 = columns[field];
14698
+ const table = column7 === void 0 ? null : foreignKeyTable(column7);
14298
14699
  const referenced = table === null ? null : site.get(table);
14299
14700
  if (referenced === null) continue;
14300
14701
  const related = await referenced.repository(dbSession).first({ [referenced.identityField]: value });
@@ -14333,6 +14734,11 @@ function inlineFieldNames(childAdmin, inline) {
14333
14734
  function inlineFields(childAdmin, names, key, values, errors) {
14334
14735
  return buildFormFields(childAdmin, { values, errors }).filter((field) => names.includes(field.name)).map((field) => ({ ...field, name: `row.${key}.${field.name}` }));
14335
14736
  }
14737
+ function jsonBlock(value) {
14738
+ if (value === null || value === void 0) return null;
14739
+ if (typeof value === "object" && Object.keys(value).length === 0) return null;
14740
+ return JSON.stringify(value, null, 2);
14741
+ }
14336
14742
  async function audit(hook, entry) {
14337
14743
  if (hook === void 0) return;
14338
14744
  try {
@@ -14496,7 +14902,7 @@ function csvField(value) {
14496
14902
  function toCsv(columns, rows) {
14497
14903
  const lines = [columns.map(csvField).join(",")];
14498
14904
  for (const row of rows) {
14499
- lines.push(columns.map((column6) => csvField(exportValue(row[column6]))).join(","));
14905
+ lines.push(columns.map((column7) => csvField(exportValue(row[column7]))).join(","));
14500
14906
  }
14501
14907
  return `${lines.join("\r\n")}\r
14502
14908
  `;
@@ -14504,7 +14910,7 @@ function toCsv(columns, rows) {
14504
14910
  function toJson(columns, rows) {
14505
14911
  return JSON.stringify(
14506
14912
  rows.map(
14507
- (row) => Object.fromEntries(columns.map((column6) => [column6, exportValue(row[column6])]))
14913
+ (row) => Object.fromEntries(columns.map((column7) => [column7, exportValue(row[column7])]))
14508
14914
  ),
14509
14915
  null,
14510
14916
  2
@@ -16460,6 +16866,6 @@ async function withTestDatabase(models, fn) {
16460
16866
  }
16461
16867
  }
16462
16868
 
16463
- export { ADMIN_CSS, ActivationService, AdminJsonSite, AdminModel, AdminPermission, AdminSessionStore, AdminSite, AppException, AttemptThrottle, AuditAction, BaseAuditLogModel, BaseController, BaseModel, BaseOAuthClient, BaseOutboxModel, BaseService, BaseUserModel, BaseUserRefreshTokenModel, BaseUserTokenModel, CEP_PATTERN, CNPJ_PATTERN, CPF_PATTERN, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, CircuitOpenError, CompositeFeatureFlagBackend, ConflictException, DEFAULT_DOCS_FAVICON, DEFAULT_LOCALE, EmailProvider, EmailUtils, EnvFeatureFlagBackend, EventStream, ExpiredTokenException, FeatureFlags, ForbiddenException, GitHubOAuthClient, GoogleOAuthClient, GracefulShutdown, HTTPClient, HTTP_500_LOG_FILE, HTTP_500_MARKER, HttpMetrics, IDEMPOTENCY_HEADER, InvalidTokenException, JSONLogger, JWTUtils, LEVEL_LOG_FILES, LocalUploadStorage, MemoryBroker, MemoryCacheManager, MemoryFeatureFlagBackend, MemoryIdempotencyStore, MemoryRateLimitStore, MemorySessionStore, MemoryThrottleBackend, MessageCatalog, MessagingHub, MetricsUtils, MfaService, MultipartLimitError, NotFoundException, OAuthError, OIDCProvider, OutboxRelay, OutboxStatus, PHONE_BR_PATTERN, PasswordResetService, REDOC_CDN_URL, REQUEST_ID_HEADER, RabbitBroker, RedisCacheManager, RedisIdempotencyStore, RedisRateLimitStore, RedisSSEBroker, RedisSessionStore, Region, RetryPolicy, S3UploadStorage, SSEBroker, ServerSentEvent, SessionService, SqlCapability, TOTPHelper, TaskManager, TelegramProvider, TenantScopedRepository, TooManyRequestsException, TwilioSmsProvider, UF, UnauthorizedException, UserAuthService, UserModelAuthBackend, UserTokenPurpose, ValidationException, WebPushDispatcher, WebPushError, WebPushGoneError, WebSocketHub, WebhookSignatureVerifier, WhatsAppProvider, activationSchema, addLogSink, adminAction, adminColumns, adminInline, adminLens, adminThemeCss, analyzeSql, attachWebSocketHub, authResponseSchema, authSettingsShape, backupDatabase, bearerToken, bodySizeLimitMiddleware, broadcastText, buildContentDisposition, buildFormFields, buildPaginationLinkHeader, cached2 as cached, cepField, checkSqlPolicy, citiesByUf, cnpjField, coerceFlag, configureFileLogging, configureLogging, cpfField, cpfOrCnpjField, createApp, createOpenApiRegistry, createTestDatabase, createdByColumn, csrfMiddleware, csrfTokenMatches, cursorPaginationFilterSchema, cursorPaginationSchema, decodeCursor, defaultMessageCatalog, defineEnum, deletedAtColumn, diffSnapshots, emailSettingsShape, encodeCursor, envList, escapeHtml, filterForColumn, filterLogEntries, foreignKeyFields, foreignKeyLabel, foreignKeyTable, formatCellValue, formatFieldValue, generateCsrfToken, generateOAuthState, generateOpaqueToken, generateOpenApiDocument, getAuth, getClientIp, getConditions, getPaginationConditions, getRequestId, getState, groupInlineSubmission, hashOpaqueToken, humanizeField, idempotencyMiddleware, inboundMessageSchema, isColumnOptional, isMultipart, isSearchableColumn, isValidCep, isValidCity, isValidCnpj, isValidCpf, isValidCpfCnpj, isValidPhoneBr, isValidUf, jwtSettingsShape, keyByHeader, keyByIp, keyByJwtClaim, keyByJwtSubject, listStates, loadSqlParser, logEntrySchema, logSettingsShape, loginSchema, makeAdminJsonRouter, makeAdminRouter, makeAppExceptionHandler, makeAuthRouter, makeFlagGuard, makeHealthRouter, makeJwtAuthMiddleware, makeLogsRouter, makeMetricsRouter, makeSessionMiddleware, makeToolSpecRouter, makeTwilioWebhookRouter, makeUnhandledExceptionHandler, makeWhatsAppWebhookRouter, metricCard, mfaChallengeSchema, mfaCodeSchema, mfaEnrollResponseSchema, minioSettingsShape, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, parseCookies, parseCsv, parseFormBody, parseMultipart, partitionTotal, passwordResetConfirmSchema, passwordResetRequestSchema, phoneBrField, prometheusMiddleware, rabbitmqSettingsShape, rateLimitMiddleware, readLogEntries, redisSettingsShape, refreshSchema, registerExceptionHandlers, renderAuthResultPage, renderDashboardPage, renderDetailPage, renderFormPage, renderImportPage, renderLayout, renderListPage, renderLogEntriesJson, renderLogEntriesMarkdown, renderLoginPage, renderLogsPage, renderMfaPage, renderPasswordResetFormPage, renderSqlPage, requestIdMiddleware, requestTracingMiddleware, requireRoles, resolveAdminTheme, resolveDownloadPath, resolveRedocBundle, runServer, runWithRequestContext, sendBytesDownload, sendFileDownload, sessionCookie, sessionSettingsShape, setRequestId, signupSchema, snapshot, sseResponse, statesByRegion, syncFilterSchema, syncPaginationSchema, tableNameFor, toLogEntry, toUtc, tokenFromUrl, tokenPairSchema, tokenSettingsShape, trendDirection, trendPercent, ufField, updatedByColumn, uploadSettingsShape, userPublicSchema, utcnow, validateTwilioSignature, verifyOpaqueToken, webPushKeysSchema, webPushPayloadSchema, webPushSettingsShape, webPushSubscriptionSchema, webSocketSettingsShape, widgetForColumn, withTestDatabase, wrapWithSlowQueryLog, wsEnvelopeSchema };
16869
+ export { ADMIN_CSS, ActivationService, AdminJsonSite, AdminModel, AdminPermission, AdminSessionStore, AdminSite, AppException, AttemptThrottle, AuditAction, BaseAuditLogModel, BaseController, BaseJobModel, BaseModel, BaseOAuthClient, BaseOutboxModel, BaseService, BaseUserModel, BaseUserRefreshTokenModel, BaseUserTokenModel, CEP_PATTERN, CNPJ_PATTERN, CPF_PATTERN, CSRF_COOKIE_NAME, CSRF_HEADER_NAME, CircuitOpenError, CompositeFeatureFlagBackend, ConflictException, DEFAULT_DOCS_FAVICON, DEFAULT_LOCALE, EmailProvider, EmailUtils, EnvFeatureFlagBackend, EventStream, ExpiredTokenException, FeatureFlags, ForbiddenException, GitHubOAuthClient, GoogleOAuthClient, GracefulShutdown, HTTPClient, HTTP_500_LOG_FILE, HTTP_500_MARKER, HttpMetrics, IDEMPOTENCY_HEADER, InvalidTokenException, JSONLogger, JWTUtils, JobStatus, JobStore, LEVEL_LOG_FILES, LocalUploadStorage, MemoryBroker, MemoryCacheManager, MemoryFeatureFlagBackend, MemoryIdempotencyStore, MemoryRateLimitStore, MemorySessionStore, MemoryThrottleBackend, MessageCatalog, MessagingHub, MetricsUtils, MfaService, MultipartLimitError, NotFoundException, OAuthError, OIDCProvider, OutboxRelay, OutboxStatus, PHONE_BR_PATTERN, PasswordResetService, REDOC_CDN_URL, REQUEST_ID_HEADER, RabbitBroker, RedisCacheManager, RedisIdempotencyStore, RedisRateLimitStore, RedisSSEBroker, RedisSessionStore, Region, RetryPolicy, S3UploadStorage, SSEBroker, ServerSentEvent, SessionService, SqlCapability, TOTPHelper, TaskManager, TelegramProvider, TenantScopedRepository, TooManyRequestsException, TwilioSmsProvider, UF, UnauthorizedException, UserAuthService, UserModelAuthBackend, UserTokenPurpose, ValidationException, WebPushDispatcher, WebPushError, WebPushGoneError, WebSocketHub, WebhookSignatureVerifier, WhatsAppProvider, activationSchema, addLogSink, adminAction, adminColumns, adminInline, adminLens, adminThemeCss, analyzeSql, attachWebSocketHub, authResponseSchema, authSettingsShape, backupDatabase, bearerToken, bodySizeLimitMiddleware, broadcastText, buildContentDisposition, buildFormFields, buildPaginationLinkHeader, cached2 as cached, cepField, checkSqlPolicy, citiesByUf, cnpjField, coerceFlag, configureFileLogging, configureLogging, cpfField, cpfOrCnpjField, createApp, createOpenApiRegistry, createTestDatabase, createdByColumn, csrfMiddleware, csrfTokenMatches, cursorPaginationFilterSchema, cursorPaginationSchema, decodeCursor, defaultMessageCatalog, defineEnum, deletedAtColumn, diffSnapshots, emailSettingsShape, encodeCursor, envList, escapeHtml, filterForColumn, filterLogEntries, foreignKeyFields, foreignKeyLabel, foreignKeyTable, formatCellValue, formatFieldValue, generateCsrfToken, generateOAuthState, generateOpaqueToken, generateOpenApiDocument, getAuth, getClientIp, getConditions, getPaginationConditions, getRequestId, getState, groupInlineSubmission, hashOpaqueToken, humanizeField, idempotencyMiddleware, inboundMessageSchema, isColumnOptional, isMultipart, isSearchableColumn, isValidCep, isValidCity, isValidCnpj, isValidCpf, isValidCpfCnpj, isValidPhoneBr, isValidUf, jwtSettingsShape, keyByHeader, keyByIp, keyByJwtClaim, keyByJwtSubject, listStates, loadSqlParser, logEntrySchema, logSettingsShape, loginSchema, makeAdminJsonRouter, makeAdminRouter, makeAppExceptionHandler, makeAuthRouter, makeFlagGuard, makeHealthRouter, makeJwtAuthMiddleware, makeLogsRouter, makeMetricsRouter, makeSessionMiddleware, makeToolSpecRouter, makeTwilioWebhookRouter, makeUnhandledExceptionHandler, makeWhatsAppWebhookRouter, metricCard, mfaChallengeSchema, mfaCodeSchema, mfaEnrollResponseSchema, minioSettingsShape, modifyDict, mountOpenApiJson, mountRedoc, mountSwaggerUi, normalizeCep, normalizeCnpj, normalizeCpf, normalizeCpfCnpj, normalizePhoneBr, normalizeUf, notFoundHandler, onlyDigits, paginationFilterSchema, paginationSchema, parseAcceptLanguage, parseCookies, parseCsv, parseFormBody, parseMultipart, partitionTotal, passwordResetConfirmSchema, passwordResetRequestSchema, phoneBrField, prometheusMiddleware, rabbitmqSettingsShape, rateLimitMiddleware, readLogEntries, redisSettingsShape, refreshSchema, registerExceptionHandlers, renderAuthResultPage, renderDashboardPage, renderDetailPage, renderFormPage, renderImportPage, renderLayout, renderListPage, renderLogEntriesJson, renderLogEntriesMarkdown, renderLoginPage, renderLogsPage, renderMfaPage, renderPasswordResetFormPage, renderSqlPage, renderTaskDetailPage, renderTasksPage, requestIdMiddleware, requestTracingMiddleware, requireRoles, resolveAdminTheme, resolveDownloadPath, resolveRedocBundle, runServer, runWithRequestContext, sendBytesDownload, sendFileDownload, sessionCookie, sessionSettingsShape, setRequestId, signupSchema, snapshot, sseResponse, statesByRegion, syncFilterSchema, syncPaginationSchema, tableNameFor, toLogEntry, toUtc, tokenFromUrl, tokenPairSchema, tokenSettingsShape, trendDirection, trendPercent, ufField, updatedByColumn, uploadSettingsShape, userPublicSchema, utcnow, validateTwilioSignature, verifyOpaqueToken, webPushKeysSchema, webPushPayloadSchema, webPushSettingsShape, webPushSubscriptionSchema, webSocketSettingsShape, widgetForColumn, withTestDatabase, wrapWithSlowQueryLog, wsEnvelopeSchema };
16464
16870
  //# sourceMappingURL=index.js.map
16465
16871
  //# sourceMappingURL=index.js.map