@docstack/client 0.0.1

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 (77) hide show
  1. package/README.md +214 -0
  2. package/lib/core/attribute.d.ts +174 -0
  3. package/lib/core/attribute.js +296 -0
  4. package/lib/core/attribute.js.map +1 -0
  5. package/lib/core/class.d.ts +340 -0
  6. package/lib/core/class.js +540 -0
  7. package/lib/core/class.js.map +1 -0
  8. package/lib/core/crypto-engine/index.d.ts +121 -0
  9. package/lib/core/crypto-engine/index.js +130 -0
  10. package/lib/core/crypto-engine/index.js.map +1 -0
  11. package/lib/core/crypto-engine/utils.d.ts +20 -0
  12. package/lib/core/crypto-engine/utils.js +76 -0
  13. package/lib/core/crypto-engine/utils.js.map +1 -0
  14. package/lib/core/datamodel/index.d.ts +3 -0
  15. package/lib/core/datamodel/index.js +1186 -0
  16. package/lib/core/datamodel/index.js.map +1 -0
  17. package/lib/core/domain.d.ts +200 -0
  18. package/lib/core/domain.js +285 -0
  19. package/lib/core/domain.js.map +1 -0
  20. package/lib/core/index.d.ts +176 -0
  21. package/lib/core/index.js +379 -0
  22. package/lib/core/index.js.map +1 -0
  23. package/lib/core/job-engine/index.d.ts +110 -0
  24. package/lib/core/job-engine/index.js +116 -0
  25. package/lib/core/job-engine/index.js.map +1 -0
  26. package/lib/core/policy-engine/index.d.ts +97 -0
  27. package/lib/core/policy-engine/index.js +150 -0
  28. package/lib/core/policy-engine/index.js.map +1 -0
  29. package/lib/core/query-engine/accumulators.d.ts +9 -0
  30. package/lib/core/query-engine/accumulators.js +258 -0
  31. package/lib/core/query-engine/accumulators.js.map +1 -0
  32. package/lib/core/query-engine/evaluator.d.ts +37 -0
  33. package/lib/core/query-engine/evaluator.js +179 -0
  34. package/lib/core/query-engine/evaluator.js.map +1 -0
  35. package/lib/core/query-engine/executor.d.ts +14 -0
  36. package/lib/core/query-engine/executor.js +405 -0
  37. package/lib/core/query-engine/executor.js.map +1 -0
  38. package/lib/core/query-engine/index.d.ts +4 -0
  39. package/lib/core/query-engine/index.js +4 -0
  40. package/lib/core/query-engine/index.js.map +1 -0
  41. package/lib/core/query-engine/parser.d.ts +10 -0
  42. package/lib/core/query-engine/parser.js +515 -0
  43. package/lib/core/query-engine/parser.js.map +1 -0
  44. package/lib/core/query-engine/planner.d.ts +27 -0
  45. package/lib/core/query-engine/planner.js +330 -0
  46. package/lib/core/query-engine/planner.js.map +1 -0
  47. package/lib/core/stack.d.ts +497 -0
  48. package/lib/core/stack.js +1507 -0
  49. package/lib/core/stack.js.map +1 -0
  50. package/lib/core/test-utils/docstack.d.ts +29 -0
  51. package/lib/core/test-utils/docstack.js +222 -0
  52. package/lib/core/test-utils/docstack.js.map +1 -0
  53. package/lib/core/trigger/index.d.ts +31 -0
  54. package/lib/core/trigger/index.js +81 -0
  55. package/lib/core/trigger/index.js.map +1 -0
  56. package/lib/index.d.ts +4 -0
  57. package/lib/index.js +8237 -0
  58. package/lib/index.js.map +1 -0
  59. package/lib/plugins/pouchdb.d.ts +9 -0
  60. package/lib/plugins/pouchdb.js +403 -0
  61. package/lib/plugins/pouchdb.js.map +1 -0
  62. package/lib/utils/crypto/index.d.ts +3 -0
  63. package/lib/utils/crypto/index.js +34 -0
  64. package/lib/utils/crypto/index.js.map +1 -0
  65. package/lib/utils/index.d.ts +4 -0
  66. package/lib/utils/index.js +58 -0
  67. package/lib/utils/index.js.map +1 -0
  68. package/lib/utils/logger/index.d.ts +4 -0
  69. package/lib/utils/logger/index.js +20 -0
  70. package/lib/utils/logger/index.js.map +1 -0
  71. package/lib/utils/logger/transport.d.ts +11 -0
  72. package/lib/utils/logger/transport.js +28 -0
  73. package/lib/utils/logger/transport.js.map +1 -0
  74. package/lib/workers/dataModel.d.ts +1 -0
  75. package/lib/workers/dataModel.js +48 -0
  76. package/lib/workers/dataModel.js.map +1 -0
  77. package/package.json +60 -0
@@ -0,0 +1,176 @@
1
+ import ClientStack from './stack';
2
+ import Class from "./class";
3
+ import Domain from './domain';
4
+ import { Trigger } from "./trigger/index";
5
+ import { JobEngine } from "./job-engine/index";
6
+ import Attribute from './attribute';
7
+ import { AttributeType, ClientCredentials, StackConfig } from "@docstack/shared";
8
+ /**
9
+ * The main entry point for the DocStack client library.
10
+ *
11
+ * DocStack manages multiple {@link ClientStack} instances and provides
12
+ * a unified interface for database operations, authentication, and
13
+ * class/attribute creation.
14
+ *
15
+ * The client emits a `ready` event when all stacks are initialized.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Initialize DocStack with a single database
20
+ * const docstack = new DocStack({ name: 'my-app' });
21
+ *
22
+ * // Wait for ready
23
+ * docstack.addEventListener('ready', async () => {
24
+ * const stack = docstack.getStack('my-app');
25
+ * const taskClass = await stack.getClass('Task');
26
+ * });
27
+ *
28
+ * // Initialize with credentials for automatic authentication
29
+ * const docstack = new DocStack({
30
+ * name: 'my-app',
31
+ * credentials: { username: 'admin', password: 'secret' }
32
+ * });
33
+ * ```
34
+ *
35
+ * @extends EventTarget
36
+ */
37
+ declare class DocStack extends EventTarget {
38
+ /** Array of stack configurations used for initialization. */
39
+ private config;
40
+ /** Whether all stacks have been initialized and ready for use. */
41
+ private readyState;
42
+ /** The primary/default stack (first in the list). */
43
+ private store;
44
+ /** Array of all initialized ClientStack instances. */
45
+ stacks: ClientStack[];
46
+ private logger;
47
+ private addStack;
48
+ private initStacks;
49
+ resetAll(): Promise<void>;
50
+ /**
51
+ * Returns all initialized stacks.
52
+ * @returns Array of ClientStack instances
53
+ */
54
+ getStacks(): ClientStack[];
55
+ /**
56
+ * Gets a stack by its name or connection string.
57
+ *
58
+ * @param name - The stack name or connection identifier
59
+ * @returns The matching ClientStack, or `undefined` if not found
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const stack = docstack.getStack('my-app');
64
+ * if (stack) {
65
+ * const users = await stack.query('SELECT * FROM User');
66
+ * }
67
+ * ```
68
+ */
69
+ getStack: (name: string) => ClientStack;
70
+ /**
71
+ * Authenticates a user on a specific stack.
72
+ *
73
+ * @param name - The stack name to authenticate against
74
+ * @param credentials - The user's login credentials
75
+ * @returns The authentication session proof
76
+ * @throws Error if the stack is not found
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const proof = await docstack.authenticateStack('my-app', {
81
+ * username: 'user@example.com',
82
+ * password: 'password123'
83
+ * });
84
+ * ```
85
+ */
86
+ authenticateStack(name: string, credentials: ClientCredentials): Promise<import("@docstack/shared").AuthSessionProof>;
87
+ /**
88
+ * Returns whether all stacks have been initialized.
89
+ * @returns `true` if ready, `false` otherwise
90
+ */
91
+ getReadyState(): boolean;
92
+ /**
93
+ * Resets all stacks and re-initializes them.
94
+ * Useful for testing or clearing all data.
95
+ */
96
+ reset(): Promise<void>;
97
+ clearConnection: (conn: string) => Promise<void>;
98
+ /**
99
+ * Exports all documents from a stack.
100
+ *
101
+ * @param stackName - The name of the stack to export
102
+ * @returns All documents from the stack
103
+ * @throws Error if the stack is not found
104
+ */
105
+ export: (stackName: string) => Promise<PouchDB.Core.AllDocsResponse<{}>>;
106
+ /**
107
+ * Creates a new Class in the specified stack.
108
+ *
109
+ * @param stackName - The name of the stack to create the class in
110
+ * @param name - The class name
111
+ * @param config - Configuration with type and description
112
+ * @throws Error if the stack is not found
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * await docstack.createClass('my-app', 'Product', {
117
+ * type: 'class',
118
+ * description: 'Product catalog items'
119
+ * });
120
+ * ```
121
+ */
122
+ createClass: (stackName: string, name: string, config: {
123
+ type: string;
124
+ description: string;
125
+ }) => Promise<void>;
126
+ /**
127
+ * Creates a new Attribute on a Class in the specified stack.
128
+ *
129
+ * @param stackName - The name of the stack containing the class
130
+ * @param className - The class to add the attribute to
131
+ * @param params - Attribute configuration
132
+ * @throws Error if the stack or class is not found
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * await docstack.createAttribute('my-app', 'Product', {
137
+ * name: 'price',
138
+ * type: 'number',
139
+ * description: 'Product price in cents'
140
+ * });
141
+ * ```
142
+ */
143
+ createAttribute: (stackName: string, className: string, params: {
144
+ name: string;
145
+ type: AttributeType["type"];
146
+ description?: string;
147
+ config?: {};
148
+ }) => Promise<void>;
149
+ /**
150
+ * Creates a new DocStack client instance.
151
+ * Initializes all configured stacks asynchronously.
152
+ * Listen for the `ready` event to know when initialization is complete.
153
+ *
154
+ * @param config - One or more stack configurations
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * const docstack = new DocStack(
159
+ * { name: 'primary-db' },
160
+ * { name: 'backup-db' }
161
+ * );
162
+ *
163
+ * docstack.addEventListener('ready', () => {
164
+ * console.log('All stacks ready!');
165
+ * });
166
+ * ```
167
+ */
168
+ constructor(...config: StackConfig[]);
169
+ }
170
+ /**
171
+ * Core exports from the DocStack client library.
172
+ *
173
+ * @module @docstack/client
174
+ */
175
+ export { ClientStack, Trigger, Class, Attribute, Domain, JobEngine };
176
+ export { DocStack };
@@ -0,0 +1,379 @@
1
+ // import express, {Express} from 'express'
2
+ // import { static as exStatic } from 'express';
3
+ // import * as dotenv from "dotenv";
4
+ // import cors from "cors";
5
+ // dotenv.config({ path: './.env' })
6
+ import createlogger from "../utils/logger/index";
7
+ // import test from '../../../server/src//utils/dbManager/test';
8
+ // import { generateJwtKeys, generatePswKeys } from '../../../server/src/utils/crypto';
9
+ import ClientStack from './stack';
10
+ // import { login, JWTAuthPayload, setupAdminUser } from '../../../server/src//utils/auth';
11
+ // import memoryAdapter from "pouchdb-adapter-memory"
12
+ // import cookieParser from 'cookie-parser';
13
+ // import jwt from 'jsonwebtoken';
14
+ import Class from "./class";
15
+ import Domain from './domain';
16
+ import { Trigger } from "./trigger/index";
17
+ import { JobEngine } from "./job-engine/index";
18
+ // import AbstractClass from '../../shared/src//utils/stack/class';
19
+ import Attribute from './attribute';
20
+ // import { EventTarget } from 'node:events';
21
+ // let envPath = process.env.ENVFILE || "./.env";
22
+ // envPath = resolve(process.cwd(), envPath);
23
+ // dotenv.config({ path: envPath });
24
+ // [TODO] Implement DocStack.type in "remote" | "local"
25
+ // When is remote, open a websocket (socket.io) connection to given remote
26
+ // implement cases in each of stack methods (queries and doc creation)
27
+ // to actually send and receive messages
28
+ // [TODO][HARD] Think about authentication mechanism
29
+ // Probably support same rest authentication (jwtToken)
30
+ // but also api tokens
31
+ // Remote connection that require auth can be opened but
32
+ // cannot send or receive messages until authentication
33
+ class DocStack extends EventTarget {
34
+ async addStack(config) {
35
+ let stack;
36
+ if (typeof config == "object" && config.name) {
37
+ stack = await ClientStack.create(`db-${config.name}`, {
38
+ // defaults to leveldb
39
+ // adapter: 'memory',
40
+ plugins: [
41
+ // https://www.npmjs.com/package/pouchdb-adapter-memory
42
+ // memoryAdapter
43
+ ],
44
+ patches: config.patches,
45
+ credentials: config.credentials,
46
+ disableCryptoEngine: config.disableCryptoEngine,
47
+ });
48
+ }
49
+ else if (typeof config === "string") {
50
+ stack = await ClientStack.create(`db-${config}`, {
51
+ // defaults to leveldb
52
+ // adapter: 'memory',
53
+ plugins: [
54
+ // https://www.npmjs.com/package/pouchdb-adapter-memory
55
+ // memoryAdapter
56
+ ]
57
+ });
58
+ }
59
+ if (stack) {
60
+ this.stacks.push(stack);
61
+ // let window_ = window as Window & typeof globalThis & {
62
+ // stacks: ClientStack[]
63
+ // }
64
+ // if (window_.stacks) {
65
+ // window_.stacks.push(stack)
66
+ // }
67
+ return stack;
68
+ }
69
+ // await setupAdminUser();
70
+ }
71
+ async resetAll() {
72
+ try {
73
+ for (const stack of this.stacks) {
74
+ await stack.reset();
75
+ }
76
+ }
77
+ catch (e) {
78
+ throw new Error(e);
79
+ }
80
+ }
81
+ getStacks() {
82
+ return this.stacks;
83
+ }
84
+ async authenticateStack(name, credentials) {
85
+ const stack = this.getStack(name);
86
+ if (!stack) {
87
+ throw new Error(`Stack '${name}' not found`);
88
+ }
89
+ return stack.authenticate(credentials);
90
+ }
91
+ getReadyState() {
92
+ return this.readyState;
93
+ }
94
+ async reset() {
95
+ try {
96
+ await this.resetAll();
97
+ await this.initStacks(this.config);
98
+ }
99
+ catch (e) {
100
+ throw new Error(e);
101
+ }
102
+ }
103
+ constructor(...config) {
104
+ super();
105
+ //private app: Express;
106
+ // private dbName: string;
107
+ this.config = [];
108
+ this.stacks = [];
109
+ this.logger = createlogger().child({ module: "client" });
110
+ this.initStacks = async (configs) => {
111
+ // TODO: Consider changing to Promise.all for concurrency
112
+ for (const config of configs) {
113
+ const stack = await this.addStack(config);
114
+ }
115
+ this.readyState = true;
116
+ this.dispatchEvent(new CustomEvent("ready", {
117
+ detail: {
118
+ stacks: this.stacks
119
+ }
120
+ }));
121
+ };
122
+ this.getStack = (name) => {
123
+ return this.stacks.find(s => s.name == name || s.connection == name);
124
+ };
125
+ this.clearConnection = async (conn) => {
126
+ const fnLogger = this.logger.child({ method: 'clearConnection' });
127
+ try {
128
+ // const conn = req.params.conn;
129
+ if (!conn) {
130
+ throw new Error("Connection name not provided");
131
+ }
132
+ await ClientStack.clear(conn);
133
+ fnLogger.info('Internal database cleared');
134
+ // return res.status(200).json({ success: true, message: 'Internal database cleared' });
135
+ }
136
+ catch (e) {
137
+ throw new Error(e);
138
+ // return res.status(500).json({ success: false, error: 'An error occurred' });
139
+ }
140
+ };
141
+ this.export = async (stackName) => {
142
+ const stack = this.getStack(stackName);
143
+ if (stack) {
144
+ const dump = await stack.dump();
145
+ return dump;
146
+ }
147
+ else {
148
+ throw new Error(`Did not find any stack for name '${stackName}'`);
149
+ }
150
+ };
151
+ this.createClass = async (name, config) => {
152
+ const fnLogger = this.logger.child({ method: 'createClass' });
153
+ const { type, description } = config;
154
+ fnLogger.info("Args", {
155
+ name, config
156
+ });
157
+ try {
158
+ const newClass = await Class.create(this.store, name, "class", description, {});
159
+ fnLogger.info(`class '${name}' created successfully.`, { classModel: newClass.getModel() });
160
+ }
161
+ catch (e) {
162
+ throw new Error(`Error during class '${name} creation. ${e}`);
163
+ }
164
+ fnLogger.info('Class created successfully');
165
+ };
166
+ this.createAttribute = async (className, params) => {
167
+ const fnLogger = this.logger.child({ method: 'createAttribute' });
168
+ const { name, type, description, config } = params;
169
+ fnLogger.info(`Creating attribute for class '${className}'`, {
170
+ name, type, config
171
+ });
172
+ try {
173
+ // Loads the class object
174
+ let classObj = await this.store.getClass(className);
175
+ if (classObj) {
176
+ let newAttribute = await Attribute.create(classObj, name, type, description, config);
177
+ fnLogger.info(`Attribute '${name}' added to class '${className}'`, { attributeModel: newAttribute.getModel() });
178
+ }
179
+ else {
180
+ throw new Error(`Failed to retrieve Class '${className}'`);
181
+ }
182
+ }
183
+ catch (e) {
184
+ fnLogger.error(`Error during attribute '${name}' creation: ${e}`);
185
+ throw new Error(`Error during attribute '${name}' creation: ${e}`);
186
+ }
187
+ };
188
+ //this.dbName = (config && config.dbName) ? config.dbName : "docstack";
189
+ // this.app = express();
190
+ this.readyState = false;
191
+ const fnLogger = this.logger.child({ method: "constructor" });
192
+ /*
193
+ this.app.use(logRequest)
194
+ // Enable CORS for all routes
195
+ if (process.env.NODE_ENV === 'development') {
196
+ logger.info("Development environment. Enabling CORS for :8080");
197
+ this.app.use(cors({
198
+ origin: 'http://localhost:8080',
199
+ // Replace with the origin of webpack dev server
200
+ methods: ['GET', 'POST'],
201
+ credentials: true,
202
+ }));
203
+ }
204
+ */
205
+ /*
206
+ // Use built-in middleware for parsing JSON and URL-encoded data
207
+ this.app.use(express.json());
208
+ this.app.use(express.urlencoded({ extended: true }));
209
+ this.app.use(cookieParser());
210
+ this.app.use((req, res, next) => {
211
+ if (!this.readyState) {
212
+ return res.status(503); // Service Unavailable.
213
+ }
214
+ // Server is ready to receive requests
215
+ next()
216
+ })
217
+ */
218
+ /*
219
+ this.app.use('/api/private', (req, res, next) => {
220
+ const token = req.cookies.jwtToken
221
+ if (!token) {
222
+ logger.error("No token provided")
223
+ return res.status(403).json({
224
+ success: false,
225
+ message: 'No token provided',
226
+ });
227
+ }
228
+ const secretKey = process.env.JWT_PUBLIC_KEY;
229
+ if (!secretKey || secretKey === '') {
230
+ logger.error("No secret key found")
231
+ return res.status(500).json({
232
+ success: false,
233
+ message: 'No secret key found',
234
+ });
235
+ }
236
+ jwt.verify(token, secretKey, async (err, payload: JWTAuthPayload) => {
237
+ if (err) {
238
+ logger.error("Invalid token", err)
239
+ return res.status(403).json({
240
+ success: false,
241
+ message: 'Invalid token',
242
+ });
243
+ } else {
244
+ // Check whether the session is still valid
245
+ const { sessionId } = payload;
246
+ const UserSessionClass = await this.store.getClass("UserSession");
247
+ const sessionCards = await UserSessionClass.getCards({
248
+ sessionId: { $eq: sessionId },
249
+ sessionStatus: { $eq: "active" }
250
+ }, null, 0, 1);
251
+ if (sessionCards.length === 0) {
252
+ return res.status(403).json({
253
+ success: false,
254
+ message: 'Session expired',
255
+ });
256
+ }
257
+ // TODO: Consider passing the session card to the next middleware
258
+ next();
259
+ }
260
+ });
261
+ })
262
+ */
263
+ // TODO: Serve the dashboard to a specific route, i.e.: admin
264
+ // this.app.use(exStatic('./dist'));
265
+ // TODO: Serve the static files from the build folder
266
+ // of the UI application
267
+ // this.app.get('*', (req, res) => {
268
+ // const templatePath = resolve(__dirname, './dist', 'index.html');
269
+ // res.sendFile(templatePath);
270
+ // });
271
+ /*
272
+ this.app.post('/login', async (req, res) => {
273
+ try {
274
+ const { username, password } = req.body;
275
+ const { responseCode, body, token } = await login(username, password);
276
+ // Append also the token to the response
277
+ let cookieOptions = {}
278
+ if (process.env.NODE_ENV === 'development') {
279
+ cookieOptions = { sameSite: 'None', secure: true, maxAge: 1000 * 60 * 15 };
280
+ logger.warn("Development mode: setting cookie options to SameSite=None; Secure=true for JWT token");
281
+ } else cookieOptions = { sameSite: 'Strict', httpOnly: true, maxAge: 1000 * 60 * 15 };
282
+
283
+ res.cookie('jwtToken', token, cookieOptions);
284
+ return res.status(responseCode).json(body);
285
+ } catch (error) {
286
+ console.error("Error during login", error);
287
+ return res.status(500).json({ success: false, error: 'An error occurred' });
288
+ }
289
+ });
290
+ */
291
+ /*
292
+ this.app.get('/api/private/reset', async (req, res) => {
293
+ try {
294
+ await this.reset();
295
+ return res.status(200).json({ success: true, message: 'Internal database reset' });
296
+ } catch (e) {
297
+ return res.status(500).json({ success: false, error: 'An error occurred' });
298
+ }
299
+ });
300
+ */
301
+ /*
302
+ this.app.get('/api/private/clear:conn', async (req, res) => {
303
+ try {
304
+ const conn = req.params.conn;
305
+ if (!conn) {
306
+ throw new Error("Connection name not provided");
307
+ }
308
+ await ClientStack.clear(conn);
309
+ return res.status(200).json({ success: true, message: 'Internal database cleared' });
310
+ } catch (e) {
311
+ logger.error("Error during database clear", e);
312
+ return res.status(500).json({ success: false, error: 'An error occurred' });
313
+ }
314
+ });
315
+ */
316
+ /*
317
+ this.app.get('/api/private/test', (req, res) => {
318
+ return res.status(200).json({ message: 'Hello from the server! This is a private route' });
319
+ });
320
+ */
321
+ /*
322
+ this.app.post('/api/private/create-class/:name', async (req, res) => {
323
+ const { name } = req.params;
324
+ const { type, description } = req.query;
325
+ logger.info("create-class - received request", {
326
+ params: req.params,
327
+ query: req.query
328
+ })
329
+
330
+ try {
331
+ const newClass = await Class.create(
332
+ this.store, name, type as string, description as string
333
+ );
334
+ logger.info("create-class", `class '${name}' created successfully.`,
335
+ {classModel: newClass.getModel()}
336
+ )
337
+ } catch (e) {
338
+ logger.error(`Error during class '${name} creation: ${e}`);
339
+ return res.status(500).json({ success: false, error: 'An error occurred' });
340
+ }
341
+
342
+ return res.status(200).json({ success: true, message: 'Class created successfully' });
343
+ })
344
+ */
345
+ /*
346
+ this.app.put('/api/private/create-attribute/:name', async (req, res) => {
347
+ const className = req.params.name;
348
+ const { name, type, config } = req.body;
349
+ logger.info(`create-attribute - for class '${className}'`, {
350
+ name, type, config
351
+ });
352
+
353
+ try {
354
+ // Loads the class object
355
+ let classObj = await this.store.getClass(className);
356
+ let newAttribute = await Attribute.create(classObj, name, type, config);
357
+ logger.info(`create-attribute - Attribute '${name}' added to class '${className}'`,
358
+ {attributeModel: newAttribute.getModel()}
359
+ );
360
+ } catch (e) {
361
+ logger.error(`Error during attribute '${name}' creation: ${e}`)
362
+ }
363
+ })
364
+ */
365
+ // const port = process.env.SERVER_PORT || 5000;
366
+ // const server = this.app.listen(port, () => logger.info(`Listening on port ${port}`));
367
+ // Procedure that should run once only
368
+ // can be considered "setup procedures"
369
+ //generatePswKeys()
370
+ // generateJwtKeys()
371
+ // Server "startup procedures"
372
+ // setTimeout(test, 1000)
373
+ this.initStacks(config);
374
+ this.addEventListener("ready", () => fnLogger.info("DocStack client successfully initialized"));
375
+ }
376
+ }
377
+ export { ClientStack, Trigger, Class, Attribute, Domain, JobEngine };
378
+ export { DocStack };
379
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ import type ClientStack from "../stack.js";
2
+ import type { JobModel, JobRunModel, JobTriggerType } from "@docstack/shared";
3
+ /**
4
+ * Represents an executable job that can perform background tasks.
5
+ *
6
+ * Jobs are stored as documents with executable content that is verified
7
+ * via hash before execution. They support singleton mode (only one instance
8
+ * can run at a time), metadata persistence, and run history tracking.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // Jobs are typically executed via JobEngine
13
+ * const run = await stack.jobEngine.executeJob('Job-auth', {
14
+ * password: 'user-password',
15
+ * salt: 'user-salt'
16
+ * });
17
+ * console.log('Job result:', run.finalMetadata);
18
+ * ```
19
+ */
20
+ export declare class Job {
21
+ /** The JobModel document containing job configuration and content. */
22
+ readonly model: JobModel;
23
+ /** Reference to the parent stack for database operations. */
24
+ private readonly stack;
25
+ private constructor();
26
+ /**
27
+ * Creates a validated Job instance from a JobModel document.
28
+ * Verifies the content hash to ensure integrity.
29
+ *
30
+ * @param model - The JobModel document from the database
31
+ * @param stack - The parent ClientStack instance
32
+ * @returns A validated Job instance
33
+ * @throws Error if the content hash doesn't match
34
+ */
35
+ static create(model: JobModel, stack: ClientStack): Promise<Job>;
36
+ /**
37
+ * Hydrates the job content into an executable function.
38
+ * The job content must define an `execute(stack, params, job)` function.
39
+ */
40
+ private hydrate;
41
+ private hasRunningInstance;
42
+ private buildRun;
43
+ private persistRun;
44
+ private persistJobMetadata;
45
+ /**
46
+ * Executes the job with optional runtime arguments.
47
+ *
48
+ * Creates a JobRun document to track execution, handles singleton logic,
49
+ * and persists any metadata updates from the job execution.
50
+ *
51
+ * @param runtimeArgs - Optional parameters to pass to the job
52
+ * @param triggerType - How the job was triggered ('manual', 'scheduled', etc.)
53
+ * @returns The completed JobRunModel with status and results
54
+ * @throws Error if the job is disabled or a singleton instance is already running
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const run = await job.execute({ userId: 'user-123' }, 'manual');
59
+ * if (run.status === 'SUCCESS') {
60
+ * console.log('Result:', run.finalMetadata);
61
+ * }
62
+ * ```
63
+ */
64
+ execute(runtimeArgs?: Record<string, any>, triggerType?: JobTriggerType): Promise<JobRunModel>;
65
+ }
66
+ /**
67
+ * Engine for executing background jobs in the DocStack system.
68
+ *
69
+ * The JobEngine provides a simple interface to execute jobs by their ID.
70
+ * Jobs are fetched from the database, validated, and executed with
71
+ * full run tracking and metadata persistence.
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * // Execute a job
76
+ * const run = await stack.jobEngine.executeJob('Job-process-data', {
77
+ * batchSize: 100
78
+ * });
79
+ *
80
+ * console.log('Status:', run.status);
81
+ * console.log('Duration:', run.durationMs, 'ms');
82
+ * ```
83
+ */
84
+ export declare class JobEngine {
85
+ /** Reference to the parent stack for database operations. */
86
+ private readonly stack;
87
+ /**
88
+ * Creates a new JobEngine instance.
89
+ * @param stack - The parent ClientStack instance
90
+ */
91
+ constructor(stack: ClientStack);
92
+ /**
93
+ * Executes a job by its document ID.
94
+ *
95
+ * @param jobId - The job document ID (e.g., 'Job-auth')
96
+ * @param runtimeArgs - Optional parameters to pass to the job
97
+ * @param triggerType - How the job was triggered (default: 'manual')
98
+ * @returns The completed JobRunModel with execution results
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * const authRun = await jobEngine.executeJob('Job-auth', {
103
+ * password: 'secret',
104
+ * salt: 'user-salt'
105
+ * });
106
+ * const derivedKey = authRun.finalMetadata?.derivedKey;
107
+ * ```
108
+ */
109
+ executeJob(jobId: string, runtimeArgs?: Record<string, any>, triggerType?: JobTriggerType): Promise<JobRunModel>;
110
+ }