@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,168 @@
1
+ import type { AppIR, EntityIR, FieldIR, Operation, PermissionIR } from "@tekki-forge/compiler";
2
+ import { type Decision } from "@tekki-forge/runtime-permissions";
3
+ import { ComputedEngine } from "./computed.js";
4
+ import { EventBus } from "./events.js";
5
+ import { NotificationService, type MailSender } from "./notifications.js";
6
+ import type { EntityExtension, EntityHooks, ForgeRequestContext, HookContext } from "./extension.js";
7
+ import { type QueryAccess } from "./query.js";
8
+ import { ApiKeyService } from "./api-keys.js";
9
+ type Row = Record<string, any>;
10
+ type Db = any;
11
+ /** Provided by the storage plugin; required when the schema has file or image fields. */
12
+ export interface FileStore {
13
+ /** Check that `fileId` may be attached to this field (uploaded here, right field, caller allowed). Returns an error message or null. */
14
+ validateAttachment(db: Db, input: {
15
+ entity: EntityIR;
16
+ field: FieldIR;
17
+ fileId: string;
18
+ ctx: ForgeRequestContext;
19
+ recordId?: string;
20
+ }): Promise<string | null>;
21
+ attach(db: Db, input: {
22
+ entity: EntityIR;
23
+ field: FieldIR;
24
+ fileId: string;
25
+ recordId: string;
26
+ }): Promise<void>;
27
+ /** Called after commit for files that are no longer referenced. */
28
+ release(fileIds: string[]): Promise<void>;
29
+ }
30
+ export interface ForgeServiceOptions {
31
+ app: AppIR;
32
+ prisma: any;
33
+ auth: any;
34
+ extensions?: EntityExtension[];
35
+ /** `Prisma.DbNull` from the generated client, used to clear JSON columns. */
36
+ dbNull?: unknown;
37
+ /** Social providers with credentials configured; exposed to the sign-in page. */
38
+ socialProviders?: string[];
39
+ events?: EventBus;
40
+ files?: FileStore;
41
+ /** Templated mail service (from @tekki-forge/emails createMail). */
42
+ mail?: MailSender;
43
+ }
44
+ export declare class ForgeService {
45
+ private readonly options;
46
+ readonly app: AppIR;
47
+ readonly prisma: any;
48
+ readonly auth: any;
49
+ readonly socialProviders: string[];
50
+ readonly events: EventBus;
51
+ readonly computed: ComputedEngine;
52
+ readonly notifications: NotificationService;
53
+ readonly apiKeys: ApiKeyService;
54
+ /** Services shared between plugins and exposed to hooks via ctx.use(name). */
55
+ readonly shared: Map<string, unknown>;
56
+ private readonly byPath;
57
+ private readonly byName;
58
+ private readonly byStorage;
59
+ private readonly extensions;
60
+ constructor(options: ForgeServiceOptions);
61
+ /** Plugins attach behaviour (hooks, actions, event handlers) to the entities they contribute. */
62
+ addExtension(ext: EntityExtension): void;
63
+ /** Used by the storage plugin during setup. */
64
+ useFileStore(store: FileStore): void;
65
+ /** Startup check once plugins have been set up. */
66
+ assertReady(): void;
67
+ entity(path: string): EntityIR;
68
+ entityByName(name: string): EntityIR | undefined;
69
+ /** The entity rows were stored under (`files.entity`, `audit_logs.entity`…): stable across renames. */
70
+ entityByStorageName(storageName: string): EntityIR | undefined;
71
+ resolveContext(headers: Headers, ip?: string): Promise<ForgeRequestContext>;
72
+ get mail(): MailSender | undefined;
73
+ hookContext(entity: EntityIR, ctx: ForgeRequestContext, db?: Db): HookContext;
74
+ private require;
75
+ authorizeOp(entity: EntityIR, op: Operation, ctx: ForgeRequestContext): Extract<Decision, {
76
+ allowed: true;
77
+ }>;
78
+ private requireTenant;
79
+ baseWhere(entity: EntityIR, ctx: ForgeRequestContext, trashed?: "without" | "with" | "only"): Row[];
80
+ /** Prisma condition restricting a conditional decision (owner / policies) on lists. */
81
+ scopeWhere(entity: EntityIR, decision: Extract<Decision, {
82
+ allowed: true;
83
+ }>, ctx: ForgeRequestContext): Row[];
84
+ /** Full read scope for the caller: tenancy, soft delete and row-level permissions. */
85
+ readWhere(entity: EntityIR, ctx: ForgeRequestContext, trashed?: "without" | "with" | "only"): Row[];
86
+ policyCheck(entity: EntityIR, ctx: ForgeRequestContext): (name: string, record: Row) => boolean | Promise<boolean>;
87
+ queryAccess(entity: EntityIR, ctx: ForgeRequestContext): QueryAccess;
88
+ /** Load a record the caller may apply `op` (or `rule`) to; 404 when they cannot even see it. Raw Prisma row. */
89
+ loadFor(entity: EntityIR, id: string, op: Operation, ctx: ForgeRequestContext, opts?: {
90
+ trashed?: "without" | "with" | "only";
91
+ rule?: PermissionIR;
92
+ }): Promise<Row>;
93
+ delegate(entity: EntityIR, db?: Db): any;
94
+ /** Serialize for this caller, dropping fields they may not read. */
95
+ present(entity: EntityIR, record: Row, ctx: ForgeRequestContext): Promise<Row>;
96
+ /** Explain why read-only keys cannot be written instead of a generic "unknown field". */
97
+ private rejectReadOnly;
98
+ private validate;
99
+ private finalizeJson;
100
+ private relationTargetsExist;
101
+ /** Field-level write permissions, ownership assignment and cross-tenant integrity of relations and files. */
102
+ private checkWrite;
103
+ private checkManyToMany;
104
+ private checkFile;
105
+ private checkManyToOne;
106
+ /** Attach newly referenced files; returns ids of files no longer referenced (released after commit). */
107
+ private syncFiles;
108
+ private audit;
109
+ private emit;
110
+ private tx;
111
+ list(entity: EntityIR, query: Row, ctx: ForgeRequestContext): Promise<{
112
+ data: any[];
113
+ meta: {
114
+ page: number;
115
+ pageSize: number;
116
+ total: any;
117
+ pages: number;
118
+ };
119
+ }>;
120
+ exportCsv(entity: EntityIR, query: Row, ctx: ForgeRequestContext): Promise<string>;
121
+ get(entity: EntityIR, id: string, ctx: ForgeRequestContext, query?: Row): Promise<Row>;
122
+ create(entity: EntityIR, body: unknown, ctx: ForgeRequestContext, options?: {
123
+ auditAction?: string;
124
+ }): Promise<Row>;
125
+ update(entity: EntityIR, id: string, body: unknown, ctx: ForgeRequestContext): Promise<Row>;
126
+ remove(entity: EntityIR, id: string, ctx: ForgeRequestContext): Promise<void>;
127
+ bulkDelete(entity: EntityIR, body: unknown, ctx: ForgeRequestContext): Promise<{
128
+ deleted: number;
129
+ }>;
130
+ restore(entity: EntityIR, id: string, ctx: ForgeRequestContext): Promise<Row>;
131
+ transition(entity: EntityIR, id: string, name: string, body: unknown, ctx: ForgeRequestContext): Promise<Row>;
132
+ runAction(entity: EntityIR, id: string, name: string, body: unknown, ctx: ForgeRequestContext): Promise<{
133
+ ok: boolean;
134
+ result: {} | null;
135
+ }>;
136
+ lookup(entity: EntityIR, query: Row, ctx: ForgeRequestContext): Promise<{
137
+ data: any;
138
+ }>;
139
+ lookupUsers(query: Row, ctx: ForgeRequestContext): Promise<{
140
+ data: any;
141
+ }>;
142
+ stats(ctx: ForgeRequestContext): Promise<{
143
+ data: {
144
+ entity: string;
145
+ path: string;
146
+ label: string;
147
+ count: number;
148
+ }[];
149
+ }>;
150
+ auditLogs(query: Row, ctx: ForgeRequestContext): Promise<{
151
+ data: any;
152
+ meta: {
153
+ page: number;
154
+ pageSize: number;
155
+ total: any;
156
+ pages: number;
157
+ };
158
+ }>;
159
+ private parse;
160
+ }
161
+ /** The person a write is made for: the signed-in user, or the creator of the API key in use. */
162
+ export declare function actingUserId(ctx: ForgeRequestContext): string;
163
+ /**
164
+ * Run both hook sets: the added hooks first (e.g. plugin limits), then the existing ones (your extension).
165
+ * before* hooks may return replacement data, which is passed along the chain.
166
+ */
167
+ export declare function composeHooks(existing?: EntityHooks, added?: EntityHooks): EntityHooks | undefined;
168
+ export {};