@tekki-forge/runtime-api 0.1.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.
Files changed (74) hide show
  1. package/README.md +5 -0
  2. package/dist/access.d.ts +15 -0
  3. package/dist/access.js +51 -0
  4. package/dist/access.js.map +1 -0
  5. package/dist/api-keys.d.ts +140 -0
  6. package/dist/api-keys.js +361 -0
  7. package/dist/api-keys.js.map +1 -0
  8. package/dist/backup.d.ts +142 -0
  9. package/dist/backup.js +280 -0
  10. package/dist/backup.js.map +1 -0
  11. package/dist/bootstrap.d.ts +57 -0
  12. package/dist/bootstrap.js +191 -0
  13. package/dist/bootstrap.js.map +1 -0
  14. package/dist/comments.d.ts +139 -0
  15. package/dist/comments.js +370 -0
  16. package/dist/comments.js.map +1 -0
  17. package/dist/computed.d.ts +27 -0
  18. package/dist/computed.js +174 -0
  19. package/dist/computed.js.map +1 -0
  20. package/dist/controllers.d.ts +309 -0
  21. package/dist/controllers.js +634 -0
  22. package/dist/controllers.js.map +1 -0
  23. package/dist/dashboard.d.ts +58 -0
  24. package/dist/dashboard.js +258 -0
  25. package/dist/dashboard.js.map +1 -0
  26. package/dist/errors.d.ts +6 -0
  27. package/dist/errors.js +55 -0
  28. package/dist/errors.js.map +1 -0
  29. package/dist/events.d.ts +39 -0
  30. package/dist/events.js +36 -0
  31. package/dist/events.js.map +1 -0
  32. package/dist/extension.d.ts +103 -0
  33. package/dist/extension.js +8 -0
  34. package/dist/extension.js.map +1 -0
  35. package/dist/import.d.ts +69 -0
  36. package/dist/import.js +347 -0
  37. package/dist/import.js.map +1 -0
  38. package/dist/index.d.ts +22 -0
  39. package/dist/index.js +23 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/jobs.d.ts +41 -0
  42. package/dist/jobs.js +10 -0
  43. package/dist/jobs.js.map +1 -0
  44. package/dist/notifications.d.ts +61 -0
  45. package/dist/notifications.js +195 -0
  46. package/dist/notifications.js.map +1 -0
  47. package/dist/plugin.d.ts +43 -0
  48. package/dist/plugin.js +4 -0
  49. package/dist/plugin.js.map +1 -0
  50. package/dist/query.d.ts +29 -0
  51. package/dist/query.js +192 -0
  52. package/dist/query.js.map +1 -0
  53. package/dist/saved-views.d.ts +42 -0
  54. package/dist/saved-views.js +130 -0
  55. package/dist/saved-views.js.map +1 -0
  56. package/dist/search.d.ts +17 -0
  57. package/dist/search.js +42 -0
  58. package/dist/search.js.map +1 -0
  59. package/dist/seed.d.ts +12 -0
  60. package/dist/seed.js +132 -0
  61. package/dist/seed.js.map +1 -0
  62. package/dist/serialize.d.ts +37 -0
  63. package/dist/serialize.js +165 -0
  64. package/dist/serialize.js.map +1 -0
  65. package/dist/service.d.ts +168 -0
  66. package/dist/service.js +757 -0
  67. package/dist/service.js.map +1 -0
  68. package/dist/teams.d.ts +63 -0
  69. package/dist/teams.js +131 -0
  70. package/dist/teams.js.map +1 -0
  71. package/dist/testing.d.ts +63 -0
  72. package/dist/testing.js +420 -0
  73. package/dist/testing.js.map +1 -0
  74. package/package.json +61 -0
@@ -0,0 +1,195 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { allowsRecord, authorize, effectiveRoles } from "@tekki-forge/runtime-permissions";
3
+ import { Logger, UnauthorizedException } from "@nestjs/common";
4
+ import { teamIdsOf } from "./teams.js";
5
+ /** Stored notifications, live delivery (SSE) and the rules declared in forge.config.ts. */
6
+ export class NotificationService {
7
+ app;
8
+ prisma;
9
+ mail;
10
+ policyCheck;
11
+ logger = new Logger("ForgeNotifications");
12
+ local = new EventEmitter();
13
+ /** Cross-instance fan-out (the jobs plugin plugs Redis pub/sub in here). */
14
+ publisher;
15
+ constructor(app, prisma, mail, policyCheck) {
16
+ this.app = app;
17
+ this.prisma = prisma;
18
+ this.mail = mail;
19
+ this.policyCheck = policyCheck;
20
+ this.local.setMaxListeners(0);
21
+ }
22
+ usePubSub(publish) {
23
+ this.publisher = publish;
24
+ }
25
+ /** Deliver a payload published by another instance to this instance's open streams. */
26
+ receive(userId, payload) {
27
+ this.local.emit(userId, payload);
28
+ }
29
+ async notify(userIds, input) {
30
+ const ids = [...new Set(userIds.filter(Boolean))];
31
+ if (!ids.length)
32
+ return 0;
33
+ const created = [];
34
+ for (const userId of ids) {
35
+ created.push(await this.prisma.notification.create({
36
+ data: {
37
+ userId,
38
+ title: input.title.slice(0, 500),
39
+ body: input.body?.slice(0, 5000) ?? null,
40
+ link: input.link ?? null,
41
+ event: input.event ?? null,
42
+ entity: input.entity ?? null,
43
+ recordId: input.recordId ?? null,
44
+ ...(this.app.tenancy.enabled ? { organizationId: input.organizationId ?? null } : {}),
45
+ },
46
+ }));
47
+ }
48
+ for (const n of created) {
49
+ const payload = { type: "notification", notification: n };
50
+ if (this.publisher)
51
+ this.publisher(n.userId, payload);
52
+ else
53
+ this.local.emit(n.userId, payload);
54
+ }
55
+ if (input.email && this.mail) {
56
+ const users = await this.prisma.user.findMany({ where: { id: { in: ids } }, select: { email: true } });
57
+ for (const u of users) {
58
+ await this.mail.send({ to: u.email, template: "notification", props: { title: input.title, body: input.body, link: input.link } }).catch((e) => this.logger.warn(`Notification email to ${u.email} failed: ${e.message}`));
59
+ }
60
+ }
61
+ return created.length;
62
+ }
63
+ // ─── Rules ────────────────────────────────────────────────────────────────────
64
+ fill(text, entity, record, actor) {
65
+ return text.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_, key) => {
66
+ if (key === "actor")
67
+ return actor;
68
+ if (key === "entity")
69
+ return entity.label;
70
+ const f = entity.fields.find((x) => x.name === key);
71
+ const v = record[key];
72
+ if (v === null || v === undefined)
73
+ return "";
74
+ if (Array.isArray(v))
75
+ return v.map((x) => x?.label ?? x).join(", ");
76
+ if (typeof v === "object")
77
+ return String(v.label ?? v.name ?? "");
78
+ if (f?.enumValues)
79
+ return f.enumValues.find((e) => e.value === v)?.label ?? String(v);
80
+ return String(v);
81
+ });
82
+ }
83
+ async principalFor(userId, organizationId, tenant) {
84
+ const user = await this.prisma.user.findUnique({ where: { id: userId }, select: { id: true, role: true, banned: true } });
85
+ if (!user || user.banned)
86
+ return null;
87
+ let memberRole = null;
88
+ if (this.app.tenancy.enabled && organizationId) {
89
+ const m = await this.prisma.member.findFirst({ where: { userId, organizationId } });
90
+ if (!m && tenant)
91
+ return null;
92
+ memberRole = m?.role ?? null;
93
+ }
94
+ const teamIds = this.app.teams?.enabled ? await teamIdsOf(this.prisma, userId, organizationId) : undefined;
95
+ return { id: userId, roles: effectiveRoles(user.role, memberRole, this.app.tenancy.enabled), organizationId, ...(teamIds ? { teamIds } : {}) };
96
+ }
97
+ async recipients(rule, entity, record, orgId) {
98
+ const ids = [];
99
+ for (const t of rule.to) {
100
+ if (t.kind === "owner" && entity.ownerField) {
101
+ const fk = entity.fields.find((f) => f.name === entity.ownerField).relation.foreignKey;
102
+ if (record[fk])
103
+ ids.push(record[fk]);
104
+ }
105
+ else if (t.kind === "field") {
106
+ const f = entity.fields.find((x) => x.name === t.field);
107
+ const v = record[f.apiName];
108
+ if (Array.isArray(v))
109
+ ids.push(...v);
110
+ else if (typeof v === "string")
111
+ ids.push(v);
112
+ }
113
+ else if (t.kind === "role") {
114
+ if (this.app.tenancy.enabled) {
115
+ const members = await this.prisma.member.findMany({ where: { organizationId: orgId ?? "__none__" }, select: { userId: true, role: true } });
116
+ for (const m of members) {
117
+ if (effectiveRoles(null, m.role, true).includes(t.role))
118
+ ids.push(m.userId);
119
+ }
120
+ }
121
+ else {
122
+ const users = await this.prisma.user.findMany({ where: { role: { contains: t.role } }, select: { id: true, role: true } });
123
+ for (const u of users)
124
+ if (effectiveRoles(u.role, null, false).includes(t.role))
125
+ ids.push(u.id);
126
+ }
127
+ }
128
+ }
129
+ return [...new Set(ids)];
130
+ }
131
+ /** Apply the configured rules to one event (subscribed on the event bus). */
132
+ async handle(event) {
133
+ const rules = this.app.notifications.filter((r) => r.entity === event.entity && r.action === event.action && (!r.name || r.name === event.name));
134
+ if (!rules.length || !event.record)
135
+ return;
136
+ const entity = this.app.entities.find((e) => e.name === event.entity);
137
+ for (const rule of rules) {
138
+ if (rule.changed && !event.changes?.[rule.changed] && !event.changes?.[entity.fields.find((f) => f.name === rule.changed)?.apiName ?? ""])
139
+ continue;
140
+ const candidates = (await this.recipients(rule, entity, event.record, event.organizationId)).filter((id) => id !== event.actor?.id);
141
+ // Only people who could see the record hear about it.
142
+ const allowed = [];
143
+ for (const userId of candidates) {
144
+ const principal = await this.principalFor(userId, event.organizationId, entity.features.tenant);
145
+ if (!principal)
146
+ continue;
147
+ const decision = authorize(entity, "read", principal);
148
+ if (await allowsRecord(entity, decision, principal, event.record, this.policyCheck?.(entity, principal)))
149
+ allowed.push(userId);
150
+ }
151
+ const actor = event.actor?.name ?? "Someone";
152
+ await this.notify(allowed, {
153
+ title: this.fill(rule.title, entity, event.record, actor),
154
+ ...(rule.body ? { body: this.fill(rule.body, entity, event.record, actor) } : {}),
155
+ link: this.fill(rule.link, entity, event.record, actor),
156
+ organizationId: event.organizationId,
157
+ entity: entity.storageName,
158
+ recordId: event.recordId,
159
+ event: event.type,
160
+ email: rule.email,
161
+ });
162
+ }
163
+ }
164
+ // ─── Per-user API ─────────────────────────────────────────────────────────────
165
+ scope(ctx) {
166
+ if (!ctx.principal)
167
+ throw new UnauthorizedException("Sign in to continue");
168
+ return {
169
+ userId: ctx.principal.id,
170
+ ...(this.app.tenancy.enabled ? { OR: [{ organizationId: ctx.principal.organizationId }, { organizationId: null }] } : {}),
171
+ };
172
+ }
173
+ async list(ctx, query) {
174
+ const where = { ...this.scope(ctx), ...(query.unread === "true" || query.unread === "1" ? { readAt: null } : {}) };
175
+ const page = Math.max(1, Number(query.page) || 1);
176
+ const pageSize = Math.min(100, Math.max(1, Number(query.pageSize) || 20));
177
+ const [total, unread, data] = await Promise.all([
178
+ this.prisma.notification.count({ where }),
179
+ this.prisma.notification.count({ where: { ...this.scope(ctx), readAt: null } }),
180
+ this.prisma.notification.findMany({ where, orderBy: { createdAt: "desc" }, skip: (page - 1) * pageSize, take: pageSize }),
181
+ ]);
182
+ return { data, unread, meta: { page, pageSize, total, pages: Math.max(1, Math.ceil(total / pageSize)) } };
183
+ }
184
+ async markRead(ctx, body) {
185
+ const where = { ...this.scope(ctx), readAt: null, ...(body?.all ? {} : { id: { in: (Array.isArray(body?.ids) ? body.ids : []).filter((x) => typeof x === "string").slice(0, 500) } }) };
186
+ const { count } = await this.prisma.notification.updateMany({ where, data: { readAt: new Date() } });
187
+ return { updated: count };
188
+ }
189
+ /** Subscribe to live notifications for this user; returns an unsubscribe function. */
190
+ subscribe(userId, send) {
191
+ this.local.on(userId, send);
192
+ return () => this.local.off(userId, send);
193
+ }
194
+ }
195
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { AppIR, PluginIR } from "@tekki-forge/compiler";
2
+ import type { DynamicModule, Type } from "@nestjs/common";
3
+ import type { EventBus } from "./events.js";
4
+ import type { FileStore, ForgeService } from "./service.js";
5
+ export interface PluginContext {
6
+ app: AppIR;
7
+ /** This plugin's compiled definition (options, env, …). */
8
+ plugin: PluginIR;
9
+ prisma: any;
10
+ service: ForgeService;
11
+ events: EventBus;
12
+ env: NodeJS.ProcessEnv;
13
+ /** Provide the store used by file and image fields (storage plugin). */
14
+ provideFileStore(store: FileStore): void;
15
+ /** Share a service with other plugins (e.g. the jobs queue), and look one up. */
16
+ provide(name: string, value: unknown): void;
17
+ use<T = unknown>(name: string): T | undefined;
18
+ }
19
+ /** The API half of a plugin, exported from "<package>/api" as a factory. */
20
+ export interface ForgeApiPlugin {
21
+ name: string;
22
+ /** Runs once at startup, before routes are registered. Throw to abort startup with a clear message. */
23
+ setup?(ctx: PluginContext): void | Promise<void>;
24
+ /** Nest controllers; they can inject FORGE_SERVICE and use `requestContext(service, req)`. */
25
+ controllers?: Type[];
26
+ /** Extra Nest modules. */
27
+ imports?: DynamicModule["imports"];
28
+ /** Paths under the API prefix that receive the raw body (Buffer) instead of parsed JSON, e.g. "/billing/webhook". */
29
+ rawBodyPaths?: string[];
30
+ /** Called after the HTTP server is listening. */
31
+ onStart?(ctx: PluginContext): void | Promise<void>;
32
+ /** Called on shutdown (SIGTERM). */
33
+ onStop?(ctx: PluginContext): void | Promise<void>;
34
+ }
35
+ export declare function definePluginRuntime<O = Record<string, unknown>>(factory: (options: O) => ForgeApiPlugin): (options?: O) => ForgeApiPlugin;
36
+ /** The worker half of a plugin, exported from "<package>/worker" (background jobs process). */
37
+ export interface ForgeWorkerPlugin {
38
+ name: string;
39
+ setup?(ctx: PluginContext): void | Promise<void>;
40
+ /** After every worker plugin's setup (handlers registered). */
41
+ onStart?(ctx: PluginContext): void | Promise<void>;
42
+ onStop?(ctx: PluginContext): void | Promise<void>;
43
+ }
package/dist/plugin.js ADDED
@@ -0,0 +1,4 @@
1
+ export function definePluginRuntime(factory) {
2
+ return (options) => factory((options ?? {}));
3
+ }
4
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAqCA,MAAM,UAAU,mBAAmB,CAA8B,OAAuC;IACtG,OAAO,CAAC,OAAW,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,IAAI,EAAE,CAAM,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { EntityIR, FieldIR } from "@tekki-forge/compiler";
2
+ export declare class QueryError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export interface ListQuery {
6
+ page: number;
7
+ pageSize: number;
8
+ orderBy: Record<string, "asc" | "desc">[];
9
+ /** Filters and search, excluding authorization/tenancy/soft-delete conditions. */
10
+ where: Record<string, unknown>[];
11
+ trashed: "without" | "with" | "only";
12
+ }
13
+ export declare const MAX_PAGE_SIZE = 500;
14
+ /** Convert one query-string value into the type Prisma expects for `f`. */
15
+ export declare function coerceFilterValue(f: FieldIR, raw: string): unknown;
16
+ export interface QueryAccess {
17
+ /** Fields the caller may filter, sort and search on (field-level read permissions). Default: all. */
18
+ queryable?: Set<string>;
19
+ /** Current user id, substituted for the `$me` filter value. */
20
+ userId?: string | null;
21
+ /** Accept filters on every readable field, not only `filterable` ones (config-declared filters, e.g. dashboards). */
22
+ anyField?: boolean;
23
+ }
24
+ export declare function sortableFields(entity: EntityIR, access?: QueryAccess): Set<string>;
25
+ export declare function searchFields(entity: EntityIR, access?: QueryAccess): FieldIR[];
26
+ export declare function searchWhere(entity: EntityIR, term: string, access?: QueryAccess): Record<string, unknown> | undefined;
27
+ export declare function parseSort(entity: EntityIR, sort: string | undefined, access?: QueryAccess): Record<string, "asc" | "desc">[];
28
+ /** Parse `?page=&pageSize=&sort=&search=&<field>=&<field>.gte=` into Prisma arguments. */
29
+ export declare function parseListQuery(entity: EntityIR, query: Record<string, unknown>, access?: QueryAccess): ListQuery;
package/dist/query.js ADDED
@@ -0,0 +1,192 @@
1
+ export class QueryError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "QueryError";
5
+ }
6
+ }
7
+ // `view` and `month` are UI state (list/board/calendar/map) that may travel with list URLs and saved views.
8
+ const RESERVED = new Set(["page", "pageSize", "sort", "search", "trashed", "view", "month"]);
9
+ const RANGE_OPS = new Set(["gte", "lte", "gt", "lt"]);
10
+ const RANGE_KINDS = new Set(["integer", "decimal", "money", "percentage", "date", "datetime"]);
11
+ export const MAX_PAGE_SIZE = 500;
12
+ function first(v) {
13
+ if (Array.isArray(v))
14
+ return v.length ? String(v[v.length - 1]) : undefined;
15
+ return v === undefined || v === null ? undefined : String(v);
16
+ }
17
+ function toInt(v, fallback, name, max = Number.MAX_SAFE_INTEGER) {
18
+ const s = first(v);
19
+ if (s === undefined || s === "")
20
+ return fallback;
21
+ const n = Number(s);
22
+ if (!Number.isInteger(n) || n < 1)
23
+ throw new QueryError(`${name} must be a positive integer`);
24
+ return Math.min(n, max);
25
+ }
26
+ /** Convert one query-string value into the type Prisma expects for `f`. */
27
+ export function coerceFilterValue(f, raw) {
28
+ if (raw === "null")
29
+ return null;
30
+ switch (f.kind) {
31
+ case "integer":
32
+ case "percentage": {
33
+ const n = Number(raw);
34
+ if (Number.isNaN(n) || (f.kind === "integer" && !Number.isInteger(n)))
35
+ throw new QueryError(`${f.name}: "${raw}" is not a number`);
36
+ return n;
37
+ }
38
+ case "decimal":
39
+ case "money":
40
+ if (!/^-?\d+(\.\d+)?$/.test(raw))
41
+ throw new QueryError(`${f.name}: "${raw}" is not a decimal`);
42
+ return raw;
43
+ case "boolean":
44
+ if (raw !== "true" && raw !== "false")
45
+ throw new QueryError(`${f.name} must be true or false`);
46
+ return raw === "true";
47
+ case "date":
48
+ case "datetime": {
49
+ const d = new Date(raw);
50
+ if (Number.isNaN(d.getTime()))
51
+ throw new QueryError(`${f.name}: "${raw}" is not a date`);
52
+ return d;
53
+ }
54
+ case "enum":
55
+ if (!f.enumValues.some((v) => v.value === raw))
56
+ throw new QueryError(`${f.name} must be one of ${f.enumValues.map((v) => v.value).join(", ")}`);
57
+ return raw;
58
+ default:
59
+ return raw;
60
+ }
61
+ }
62
+ const allowed = (f, access) => !access?.queryable || access.queryable.has(f.name);
63
+ export function sortableFields(entity, access) {
64
+ return new Set([
65
+ "id",
66
+ ...(entity.features.timestamps ? ["createdAt", "updatedAt"] : []),
67
+ ...entity.fields.filter((f) => f.sortable && !f.hidden && allowed(f, access)).map((f) => f.name),
68
+ ]);
69
+ }
70
+ export function searchFields(entity, access) {
71
+ const explicit = entity.fields.filter((f) => f.searchable && !f.hidden && allowed(f, access));
72
+ if (explicit.length)
73
+ return explicit;
74
+ const display = entity.fields.find((f) => f.name === entity.display && allowed(f, access));
75
+ return display && ["string", "text", "email", "url", "phone"].includes(display.kind) ? [display] : [];
76
+ }
77
+ export function searchWhere(entity, term, access) {
78
+ const fields = searchFields(entity, access);
79
+ const t = term.trim();
80
+ if (!t || fields.length === 0)
81
+ return undefined;
82
+ return { OR: fields.map((f) => ({ [f.name]: { contains: t, mode: "insensitive" } })) };
83
+ }
84
+ export function parseSort(entity, sort, access) {
85
+ const allowed = sortableFields(entity, access);
86
+ const spec = sort?.trim() || `${entity.list.defaultSort.direction === "desc" ? "-" : ""}${entity.list.defaultSort.field}`;
87
+ const orderBy = spec
88
+ .split(",")
89
+ .map((s) => s.trim())
90
+ .filter(Boolean)
91
+ .map((s) => {
92
+ const desc = s.startsWith("-");
93
+ const name = s.replace(/^[-+]/, "");
94
+ if (!allowed.has(name))
95
+ throw new QueryError(`cannot sort by "${name}" (sortable: ${[...allowed].join(", ")})`);
96
+ return { [name]: desc ? "desc" : "asc" };
97
+ });
98
+ // A unique tiebreaker keeps pagination stable.
99
+ if (!orderBy.some((o) => "id" in o))
100
+ orderBy.push({ id: "asc" });
101
+ return orderBy;
102
+ }
103
+ /** Parse `?page=&pageSize=&sort=&search=&<field>=&<field>.gte=` into Prisma arguments. */
104
+ export function parseListQuery(entity, query, access) {
105
+ const page = toInt(query.page, 1, "page");
106
+ const pageSize = toInt(query.pageSize, entity.list.pageSize, "pageSize", MAX_PAGE_SIZE);
107
+ const where = [];
108
+ const search = first(query.search);
109
+ if (search) {
110
+ const w = searchWhere(entity, search, access);
111
+ if (w)
112
+ where.push(w);
113
+ }
114
+ const trashed = (first(query.trashed) ?? "without");
115
+ if (!["without", "with", "only"].includes(trashed))
116
+ throw new QueryError(`trashed must be without, with or only`);
117
+ if (trashed !== "without" && !entity.features.softDelete)
118
+ throw new QueryError(`${entity.name} does not use soft delete`);
119
+ const byKey = new Map();
120
+ for (const f of entity.fields) {
121
+ if ((!f.filterable && !access?.anyField) || f.hidden || !allowed(f, access))
122
+ continue;
123
+ byKey.set(f.name, f);
124
+ byKey.set(f.apiName, f);
125
+ }
126
+ for (const [key, rawValue] of Object.entries(query)) {
127
+ if (RESERVED.has(key))
128
+ continue;
129
+ const value = first(rawValue);
130
+ if (value === undefined || value === "")
131
+ continue;
132
+ const [name, op] = key.split(".");
133
+ if ((name === "createdAt" || name === "updatedAt") && entity.features.timestamps && op && RANGE_OPS.has(op)) {
134
+ const d = new Date(value);
135
+ if (Number.isNaN(d.getTime()))
136
+ throw new QueryError(`${name}: "${value}" is not a date`);
137
+ where.push({ [name]: { [op]: d } });
138
+ continue;
139
+ }
140
+ // `<field>.set=true|false`: has a value / is empty, on any readable field.
141
+ if (op === "set" || op === "within") {
142
+ const f = entity.fields.find((x) => (x.name === name || x.apiName === name) && !x.hidden && allowed(x, access));
143
+ if (!f)
144
+ throw new QueryError(`unknown filter "${key}"`);
145
+ if (op === "set") {
146
+ if (value !== "true" && value !== "false")
147
+ throw new QueryError(`${key} must be true or false`);
148
+ const present = value === "true";
149
+ if (f.relation?.type === "many-to-many")
150
+ where.push({ [f.name]: present ? { some: {} } : { none: {} } });
151
+ else {
152
+ const column = f.kind === "location" ? `${f.name}Lat` : f.relation ? f.relation.foreignKey : f.apiName;
153
+ where.push({ [column]: present ? { not: null } : null });
154
+ }
155
+ continue;
156
+ }
157
+ // `<location>.within=south,west,north,east` (map viewport; west > east crosses the antimeridian).
158
+ if (f.kind !== "location")
159
+ throw new QueryError(`${key}: "within" only applies to location fields`);
160
+ const box = value.split(",").map(Number);
161
+ if (box.length !== 4 || box.some((n) => !Number.isFinite(n)))
162
+ throw new QueryError(`${key} must be south,west,north,east`);
163
+ const [south, west, north, east] = box;
164
+ const lng = west <= east ? { [`${f.name}Lng`]: { gte: west, lte: east } } : { OR: [{ [`${f.name}Lng`]: { gte: west } }, { [`${f.name}Lng`]: { lte: east } }] };
165
+ where.push({ [`${f.name}Lat`]: { gte: Math.min(south, north), lte: Math.max(south, north) } }, lng);
166
+ continue;
167
+ }
168
+ // Range operators work on any visible, sortable number/date field; equality needs `filterable`.
169
+ const f = byKey.get(name) ?? (op ? entity.fields.find((x) => x.name === name && x.sortable && !x.hidden && RANGE_KINDS.has(x.kind) && allowed(x, access)) : undefined);
170
+ if (!f)
171
+ throw new QueryError(`unknown filter "${key}" — filterable: ${[...new Set([...byKey.values()].map((x) => x.name))].join(", ") || "none"}`);
172
+ const column = f.relation ? f.relation.foreignKey : f.name;
173
+ const me = (v) => (v === "$me" ? (access?.userId ?? "__nobody__") : v);
174
+ if (f.relation?.type === "many-to-many") {
175
+ if (op)
176
+ throw new QueryError(`unsupported filter operator "${key}"`);
177
+ const ids = value.split(",").map((v) => me(v.trim())).filter(Boolean);
178
+ where.push(value === "null" ? { [f.name]: { none: {} } } : { [f.name]: { some: { id: { in: ids } } } });
179
+ continue;
180
+ }
181
+ if (op) {
182
+ if (!RANGE_OPS.has(op) || !RANGE_KINDS.has(f.kind))
183
+ throw new QueryError(`unsupported filter operator "${key}"`);
184
+ where.push({ [column]: { [op]: coerceFilterValue(f, value) } });
185
+ continue;
186
+ }
187
+ const values = value.split(",").map((v) => coerceFilterValue(f, f.relation ? me(v.trim()) : v.trim()));
188
+ where.push(values.length === 1 ? { [column]: values[0] } : { [column]: { in: values.filter((v) => v !== null) } });
189
+ }
190
+ return { page, pageSize, orderBy: parseSort(entity, first(query.sort), access), where, trashed };
191
+ }
192
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { EntityIR } from "@tekki-forge/compiler";
2
+ import type { ForgeRequestContext } from "./extension.js";
3
+ import type { ForgeService } from "./service.js";
4
+ type Row = Record<string, any>;
5
+ /** Saved list filters: personal, or shared with the organization by an admin. */
6
+ export declare class SavedViewService {
7
+ private readonly service;
8
+ constructor(service: ForgeService);
9
+ private get prisma();
10
+ private principal;
11
+ private orgWhere;
12
+ private readableEntity;
13
+ /** Keep only list parameters, and check they are valid for this caller (unknown or unreadable fields are rejected). */
14
+ sanitize(entity: EntityIR, query: unknown, ctx: ForgeRequestContext): Record<string, string>;
15
+ private out;
16
+ list(resource: unknown, ctx: ForgeRequestContext): Promise<{
17
+ data: any;
18
+ }>;
19
+ private name;
20
+ private checkShare;
21
+ create(body: Row, ctx: ForgeRequestContext): Promise<{
22
+ id: any;
23
+ resource: any;
24
+ name: any;
25
+ query: any;
26
+ shared: any;
27
+ mine: boolean;
28
+ createdAt: any;
29
+ }>;
30
+ private find;
31
+ update(id: string, body: Row, ctx: ForgeRequestContext): Promise<{
32
+ id: any;
33
+ resource: any;
34
+ name: any;
35
+ query: any;
36
+ shared: any;
37
+ mine: boolean;
38
+ createdAt: any;
39
+ }>;
40
+ remove(id: string, ctx: ForgeRequestContext): Promise<void>;
41
+ }
42
+ export {};