modelence 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.
- package/README.md +3 -0
- package/dist/chunk-ENW3BXAD.js +1 -0
- package/dist/client.d.ts +42 -0
- package/dist/client.js +360 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/server.d.ts +125 -0
- package/dist/server.js +3 -0
- package/dist/types-DAn43Whw.d.ts +13 -0
- package/index.ts +3 -0
- package/package.json +69 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{c as time}from'./chunk-ENW3BXAD.js';
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { a as ConfigSchema, C as ConfigKey } from './types-DAn43Whw.js';
|
|
2
|
+
import * as mongodb from 'mongodb';
|
|
3
|
+
import { ObjectId, IndexDescription, MongoClient, Collection, Filter, FindOptions, WithId, Document, OptionalUnlessRequiredId, InsertOneResult, UpdateFilter, UpdateResult, DeleteResult, AggregateOptions, AggregationCursor } from 'mongodb';
|
|
4
|
+
|
|
5
|
+
declare const SchemaTypes: {
|
|
6
|
+
readonly String: "string";
|
|
7
|
+
readonly Date: "date";
|
|
8
|
+
readonly Number: "number";
|
|
9
|
+
readonly Boolean: "boolean";
|
|
10
|
+
readonly Object: "object";
|
|
11
|
+
readonly Array: "array";
|
|
12
|
+
readonly ObjectId: "objectId";
|
|
13
|
+
};
|
|
14
|
+
type ModelSchemaType<T> = T extends string ? typeof SchemaTypes.String : T extends number ? typeof SchemaTypes.Number : T extends boolean ? typeof SchemaTypes.Boolean : T extends Date ? typeof SchemaTypes.Date : T extends Array<any> ? typeof SchemaTypes.Array : T extends ObjectId ? typeof SchemaTypes.ObjectId : T extends object ? typeof SchemaTypes.Object : never;
|
|
15
|
+
type ModelSchema<T> = {
|
|
16
|
+
[K in keyof T]: ModelSchemaType<T[K]>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
declare class Store<T extends object> {
|
|
20
|
+
private readonly name;
|
|
21
|
+
private readonly schema;
|
|
22
|
+
private readonly indexes;
|
|
23
|
+
private collection?;
|
|
24
|
+
constructor(name: string, { schema, indexes }: {
|
|
25
|
+
schema: ModelSchema<T>;
|
|
26
|
+
indexes: IndexDescription[];
|
|
27
|
+
});
|
|
28
|
+
getName(): string;
|
|
29
|
+
getSchema(): ModelSchema<T>;
|
|
30
|
+
provision(client: MongoClient): void;
|
|
31
|
+
requireCollection(): Collection<T>;
|
|
32
|
+
findOne(query: Filter<T>, options?: FindOptions): Promise<WithId<T> | null>;
|
|
33
|
+
find(query: Filter<T>, options?: {
|
|
34
|
+
sort?: Document;
|
|
35
|
+
}): mongodb.FindCursor<WithId<T>>;
|
|
36
|
+
fetch(query: Filter<T>, options?: {
|
|
37
|
+
sort?: Document;
|
|
38
|
+
}): Promise<WithId<T>[]>;
|
|
39
|
+
insertOne(document: OptionalUnlessRequiredId<T>): Promise<InsertOneResult>;
|
|
40
|
+
updateOne(selector: Filter<T>, update: UpdateFilter<T>): Promise<UpdateResult>;
|
|
41
|
+
upsertOne(selector: Filter<T>, update: UpdateFilter<T>): Promise<UpdateResult>;
|
|
42
|
+
updateMany(selector: Filter<T>, update: UpdateFilter<T>): Promise<UpdateResult>;
|
|
43
|
+
upsertMany(selector: Filter<T>, update: UpdateFilter<T>): Promise<UpdateResult>;
|
|
44
|
+
deleteOne(selector: Filter<T>): Promise<DeleteResult>;
|
|
45
|
+
deleteMany(selector: Filter<T>): Promise<DeleteResult>;
|
|
46
|
+
aggregate(pipeline: Document[], options?: AggregateOptions): AggregationCursor<Document>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type User = Document;
|
|
50
|
+
type Session = {
|
|
51
|
+
authToken: string;
|
|
52
|
+
expiresAt: Date;
|
|
53
|
+
userId: ObjectId | null;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type ClientInfo = {
|
|
57
|
+
screenWidth: number;
|
|
58
|
+
screenHeight: number;
|
|
59
|
+
windowWidth: number;
|
|
60
|
+
windowHeight: number;
|
|
61
|
+
pixelRatio: number;
|
|
62
|
+
orientation: string | null;
|
|
63
|
+
};
|
|
64
|
+
type ConnectionInfo = {
|
|
65
|
+
ip?: string;
|
|
66
|
+
userAgent?: string;
|
|
67
|
+
acceptLanguage?: string;
|
|
68
|
+
referrer?: string;
|
|
69
|
+
};
|
|
70
|
+
type Context = {
|
|
71
|
+
session: Session;
|
|
72
|
+
user: User | null;
|
|
73
|
+
clientInfo: ClientInfo;
|
|
74
|
+
connectionInfo: ConnectionInfo;
|
|
75
|
+
};
|
|
76
|
+
type Args = Record<string, unknown>;
|
|
77
|
+
type Handler<T extends any> = (args: Args, context: Context) => Promise<T> | T;
|
|
78
|
+
|
|
79
|
+
type Stores = Store<any>[];
|
|
80
|
+
type Queries = Record<string, Handler<any>>;
|
|
81
|
+
type Mutations = Record<string, Handler<any>>;
|
|
82
|
+
declare class Module {
|
|
83
|
+
readonly name: string;
|
|
84
|
+
readonly stores: Stores;
|
|
85
|
+
readonly queries: Queries;
|
|
86
|
+
readonly mutations: Mutations;
|
|
87
|
+
constructor(name: string, { stores, queries, mutations }: {
|
|
88
|
+
stores?: Stores;
|
|
89
|
+
queries?: Queries;
|
|
90
|
+
mutations?: Mutations;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
declare function startApp({ configSchema, modules }?: {
|
|
95
|
+
configSchema?: ConfigSchema;
|
|
96
|
+
modules?: Module[];
|
|
97
|
+
}): Promise<void>;
|
|
98
|
+
|
|
99
|
+
declare function createQuery<T extends any[]>(name: string, handler: Handler<T>): void;
|
|
100
|
+
|
|
101
|
+
type CronJob = {
|
|
102
|
+
alias: string;
|
|
103
|
+
params: {
|
|
104
|
+
description: string;
|
|
105
|
+
interval: number;
|
|
106
|
+
timeout: number;
|
|
107
|
+
};
|
|
108
|
+
handler: () => Promise<void>;
|
|
109
|
+
state: {
|
|
110
|
+
startTs?: number;
|
|
111
|
+
scheduledRunTs?: number;
|
|
112
|
+
isRunning: boolean;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
type CronJobInputParams = {
|
|
116
|
+
description?: string;
|
|
117
|
+
interval: number;
|
|
118
|
+
timeout?: number;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
declare function defineCronJob(alias: CronJob['alias'], { description, interval, timeout }: CronJobInputParams, handler: CronJob['handler']): void;
|
|
122
|
+
|
|
123
|
+
declare function getConfig(key: ConfigKey): string | number | boolean;
|
|
124
|
+
|
|
125
|
+
export { Module, SchemaTypes, Store, createQuery, defineCronJob, getConfig, startApp };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import {c}from'./chunk-ENW3BXAD.js';import lt from'dotenv';import Ve from'http';import L from'express';import m,{z as z$1}from'zod';import je from'elastic-apm-node';import j from'winston';import {ElasticsearchTransport}from'winston-elasticsearch';import x from'process';import {randomBytes}from'crypto';import $e from'bcrypt';import {MongoClient,ServerApiVersion,ObjectId}from'mongodb';import {createServer,defineConfig}from'vite';import Fe from'@vitejs/plugin-react';import We from'vite-plugin-eslint';import P from'path';import Be from'fs';import et from'os';function ve(){return typeof window!="object"}function h(){if(!ve())throw new Error("This function can only be called on the server")}var v={},I={},J=!1;function b(e){return I[e]?.value}function q(){if(!J)throw new Error("Config is not initialized: an attempt was made to access configs before they were loaded");return Object.fromEntries(Object.entries(I).filter(([e])=>v[e]?.isPublic))}function E(e){e.forEach(({key:t,type:r,value:o})=>{!t.toLowerCase().startsWith("_system.")&&!v[t]||(I[t]={key:t,type:r,value:o});}),J=!0;}function F(e){Object.entries(e).forEach(([t,r])=>{let{type:o,isPublic:n}=r;if(t.toLowerCase().startsWith("_system."))throw new Error(`Config key cannot start with a reserved prefix: '_system.' (${t})`);if(o==="secret"&&n)throw new Error(`Config ${t} with type "secret" cannot be public`)}),v=e;}function M(e,t){A().info(e,t);}function W(e,t){A().error(e,t);}var l={stdout:[{log:"",timestamp:null}],stderr:[{log:"",timestamp:null}]},Ie=1;function z({elasticCloudId:e,elasticApiKey:t}){let r=x.stdout.write,o=x.stderr.write;x.stdout.write=function(n,...s){return B(n,l.stdout),r.apply(x.stdout,[n,...s])},x.stderr.write=function(n,...s){return B(n,l.stderr),o.apply(x.stderr,[n,...s])},H();}function B(e,t){if(e.length===0)return;let r=new Date;for(let o=0;o<e.length;o++){let n=t[t.length-1];n.timestamp||(n.timestamp=r,n.sequenceId=Ie++),e[o]===`
|
|
2
|
+
`?t.push({log:"",timestamp:null}):n.log+=e[o];}}async function Ae(){let e=l.stdout.slice(0,-1);l.stdout=[l.stdout[l.stdout.length-1]];let t=l.stderr.slice(0,-1);l.stderr=[l.stderr[l.stderr.length-1]],e.forEach(({log:r,timestamp:o,sequenceId:n})=>{M(r,{timestamp:o,source:"console",sequenceId:n});}),t.forEach(({log:r,timestamp:o,sequenceId:n})=>{W(r,{timestamp:o,source:"console",sequenceId:n});});}function H(){setTimeout(()=>{Ae(),H();},1e3);}var K=!1,y=null,R=null,V=async()=>{if(K)throw new Error('Metrics are already initialized, duplicate "initMetrics" call received');K=!0,await _e();};async function _e(){let e=b("_system.elastic.apmEndpoint"),t=b("_system.elastic.secretToken"),r=b("_system.elastic.cloudId"),o=b("_system.elastic.apiKey");y=je.start({serviceName:"typesonic",secretToken:t,serverUrl:e,environment:"dev",transactionSampleRate:1,centralConfig:!1});let n=new ElasticsearchTransport({apm:y,level:"debug",clientOpts:{cloud:{id:r},auth:{apiKey:o},requestTimeout:1e4,tls:{rejectUnauthorized:!1}},bufferLimit:1e3,silent:!1});n.on("error",s=>{console.error("Elasticsearch Transport Error:",s);}),R=j.createLogger({level:"debug",format:j.format.combine(j.format.json()),transports:[n]}),z({elasticCloudId:r,elasticApiKey:o});}function D(e,t,r){if(!y)throw new Error("startTransaction: Elastic APM is not initialized");let o=y.startTransaction(t,e);return r&&y.setCustomContext(r),o}function Q(e){if(!y)throw new Error("captureError: Elastic APM is not initialized");y.captureError(e);}function A(){if(!R)throw new Error("Logger is not initialized");return R}var _={};function N(e,t){return h(),X(e),O("query",e,t)}function Y(e,t){return h(),X(e),O("mutation",e,t)}function G(e,t){return h(),ee(e),O("query",e,t)}function Z(e,t){return h(),ee(e),O("mutation",e,t)}function X(e){if(e.toLowerCase().startsWith("_system."))throw new Error(`Method name cannot start with a reserved prefix: '_system.' (${e})`)}function ee(e){if(!e.toLowerCase().startsWith("_system."))throw new Error(`System method name must start with a prefix: '_system.' (${e})`)}function O(e,t,r){if(h(),_[t])throw new Error(`Method with name '${t}' is already defined.`);_[t]={type:e,name:t,handler:r};}async function te(e,t,r){h();let o=_[e];if(!o)throw new Error(`Method with name '${e}' is not defined.`);let{type:n,handler:s}=o,i=D("method",`method:${e}`,{type:n,args:t}),C=await s(t,r);return i.end(),C}var u=class{constructor(t,{stores:r,queries:o,mutations:n}){this.name=t,this.stores=r??[],this.queries=o??{},this.mutations=n??{};}};var d=class{constructor(t,{schema:r,indexes:o}){this.name=t,this.schema=r,this.indexes=o;}getName(){return this.name}getSchema(){return this.schema}provision(t){this.collection||(this.collection=t.db().collection(this.name),this.collection.createIndexes(this.indexes));}requireCollection(){if(!this.collection)throw new Error(`Collection ${this.name} is not provisioned`);return this.collection}async findOne(t,r){return await this.requireCollection().findOne(t,r)}find(t,r){let o=this.requireCollection().find(t);return r?.sort&&o.sort(r.sort),o}async fetch(t,r){return await this.find(t,r).toArray()}async insertOne(t){return await this.requireCollection().insertOne(t)}async updateOne(t,r){return await this.requireCollection().updateOne(t,r)}async upsertOne(t,r){return await this.requireCollection().updateOne(t,r,{upsert:!0})}async updateMany(t,r){return await this.requireCollection().updateMany(t,r)}async upsertMany(t,r){return await this.requireCollection().updateMany(t,r,{upsert:!0})}async deleteOne(t){return await this.requireCollection().deleteOne(t)}async deleteMany(t){return await this.requireCollection().deleteMany(t)}aggregate(t,r){return this.requireCollection().aggregate(t,r)}};var a={String:"string",Date:"date",Number:"number",Boolean:"boolean",Object:"object",Array:"array",ObjectId:"objectId"};var S=new d("_modelenceSessions",{schema:{authToken:a.String,createdAt:a.Date,expiresAt:a.Date,userId:a.ObjectId},indexes:[{key:{authToken:1},unique:!0},{key:{expiresAt:1}}]});async function re(e){let t=e?await S.findOne({authToken:e}):null;return t?{authToken:String(t.authToken),expiresAt:new Date(t.expiresAt),userId:t.userId??null}:await Pe()}async function oe(e,t){await S.updateOne({authToken:e},{$set:{userId:t}});}async function Pe(){let e=randomBytes(32).toString("base64url"),t=Date.now(),r=new Date(t+c.days(7));return await S.insertOne({authToken:e,createdAt:new Date(t),expiresAt:r,userId:null}),{authToken:e,expiresAt:r,userId:null}}async function Le(e){let t=Date.now(),r=new Date(t+c.days(7));await S.updateOne({authToken:e.authToken},{$set:{lastActiveDate:new Date(t),expiresAt:r}});}var ne=new u("_system.session",{stores:[S],mutations:{init:async function(e,{session:t,user:r}){return {session:t,user:r,configs:q()}},heartbeat:async function(e,{session:t}){await Le(t);}}});async function ie(e,{user:t}){let r=z$1.string().email().parse(e.email),o=z$1.string().min(8,{message:"Password must contain at least 8 characters"}).parse(e.password),n=await p.findOne({"emails.address":r},{collation:{locale:"en",strength:2}});if(n){let C=n.emails?.find(g=>g.address===r);throw new Error(`User with email already exists: ${C?.address}`)}let s=await $e.hash(o,10);return (await p.insertOne({handle:r,emails:[{address:r,verified:!1}],createdAt:new Date,authMethods:{password:{hash:s}}})).insertedId}async function le(e,{user:t,session:r}){let o=z$1.string().email().parse(e.email),n=z$1.string().parse(e.password),s=await p.findOne({"emails.address":o},{collation:{locale:"en",strength:2}}),i=s?.authMethods?.password?.hash;if(!s||!i||!await $e.compare(n,i))throw ce();return oe(r.authToken,s._id),s._id}function ce(){return new Error("Incorrect email/password combination")}var p=new d("_modelenceUsers",{schema:{handle:a.String,emails:a.Array,createdAt:a.Date,authMethods:a.Object},indexes:[{key:{handle:1},unique:!0,collation:{locale:"en",strength:2}}]});var ue=new u("_system.user",{stores:[p],mutations:{signupWithPassword:ie,loginWithPassword:le}});async function de(e){let t=await re(e),r=t.userId?await p.findOne({_id:new ObjectId(t.userId)}):null;return {user:r?{id:r._id,handle:r.handle}:null,session:t}}async function me(e,t){if(t){console.log("Starting Vite dev server...");let r=await createServer({...defineConfig(await He()),server:{middlewareMode:!0},root:"./src/client"});e.use(r.middlewares),e.use("*",async(o,n)=>{try{n.sendFile("index.html",{root:"./src/client"});}catch(s){console.error("Error serving index.html:",s),n.status(500).send("Internal Server Error");}});}else e.use(L.static(".modelence/client")),e.get("*",(r,o)=>{o.sendFile("index.html",{root:".modelence/client"});});}async function He(){let e=process.cwd(),t=[".eslintrc.js",".eslintrc.json",".eslintrc","eslint.config.js",".eslintrc.yml",".eslintrc.yaml"].find(o=>Be.existsSync(P.join(e,o))),r=[Fe(),Ke()];return t&&r.push(We({failOnError:!1,include:["src/**/*.js","src/**/*.jsx","src/**/*.ts","src/**/*.tsx"],cwd:e,overrideConfigFile:P.resolve(e,t)})),{plugins:r,root:e,build:{outDir:".modelence/client",emptyOutDir:!0},server:{proxy:{"/api":"http://localhost:4000"},headers:{"Cache-Control":"no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0",Pragma:"no-cache",Expires:"0"}},resolve:{alias:{"@":P.resolve(e,"src")}}}}function Ke(){return {name:"modelence-asset-handler",async transform(e,t){if(/\.(png|jpe?g|gif|svg|mpwebm|ogg|mp3|wav|flac|aac)$/.test(t))return process.env.NODE_ENV==="development",e},async generateBundle(e,t){}}}async function pe(){let e=L(),t=process.env.NODE_ENV!=="production";e.use(L.json()),e.use(L.urlencoded({extended:!0})),e.post("/api/_internal/method/:methodName",async(n,s)=>{let{methodName:i}=n.params,C=await Ge(n);try{let g=await te(i,n.body.args,C);s.json(g);}catch(g){g instanceof m.ZodError?s.status(400).send(g.errors.map(Oe=>Oe.message).join("; ")):s.status(500).send(String(g));}}),await me(e,t),process.on("unhandledRejection",(n,s)=>{console.error("Unhandled Promise Rejection:"),console.error(n instanceof Error?n.stack:n),console.error("Promise:",s);}),process.on("uncaughtException",n=>{console.error("Uncaught Exception:"),console.error(n.stack),console.trace("Full application stack:");});let r=Ve.createServer(e),o=process.env.PORT||3e3;r.listen(o,()=>{M("Application started",{source:"app"}),console.log(`Application started on port ${o}`);});}async function Ge(e){let t=m.string().nullable().parse(e.body.authToken),r=m.object({screenWidth:m.number(),screenHeight:m.number(),windowWidth:m.number(),windowHeight:m.number(),pixelRatio:m.number(),orientation:m.string().nullable()}).parse(e.body.clientInfo),o={ip:e.ip||e.socket.remoteAddress,userAgent:e.get("user-agent"),acceptLanguage:e.get("accept-language"),referrer:e.get("referrer")},{session:n,user:s}=await de(t);return {clientInfo:r,connectionInfo:o,session:n,user:s}}var f=null;async function fe(e){if(f)return f;f=new MongoClient(e,{serverApi:{version:ServerApiVersion.v1,strict:!0,deprecationErrors:!0}});try{return await f.connect(),await f.db("admin").command({ping:1}),console.log("Pinged your deployment. You successfully connected to MongoDB!"),f}catch(t){throw console.error(t),f=null,t}}function ge(){return f}async function he({configSchema:e,cronJobsMetadata:t,stores:r}){let o=process.env.MODELENCE_CONTAINER_ID;if(!o)throw new Error("Unable to connect to Modelence Cloud: MODELENCE_CONTAINER_ID is not set");try{let n=Object.values(r).map(i=>({name:i.getName(),schema:i.getSchema(),collections:[i.getName()]})),s=await $("/api/connect","POST",{hostname:et.hostname(),containerId:o,dataModels:n,configSchema:e,cronJobsMetadata:t});return console.log("Successfully connected to Modelence Cloud"),s}catch(n){throw console.error("Unable to connect to Modelence Cloud:",n),n}}async function ye(){return await $("/api/configs","GET")}async function we(){return await $("/api/sync","POST",{containerId:process.env.MODELENCE_CONTAINER_ID})}async function $(e,t,r){let{MODELENCE_SERVICE_ENDPOINT:o,MODELENCE_SERVICE_TOKEN:n}=process.env;if(!o)throw new Error("Unable to connect to Modelence Cloud: MODELENCE_SERVICE_ENDPOINT is not set");let s=await fetch(`${o}/${e}`,{method:t,headers:{Authorization:`Bearer ${n}`,...r?{"Content-Type":"application/json"}:{}},body:r?JSON.stringify(r):void 0});if(!s.ok){let i=await s.json();throw new Error(`Unable to connect to Modelence Cloud: HTTP status: ${s.status}, ${i?.error}`)}return await s.json()}var U=!1,tt=c.seconds(10);function Ce(){setInterval(async()=>{if(!U){U=!0;try{await we();}catch(e){console.error("Error syncing status",e);}try{await rt();}catch(e){console.error("Error syncing config",e);}U=!1;}},tt);}async function rt(){let{configs:e}=await ye();E(e);}var be=!1;function xe(){be=!0;}function Se(){return be}var ot=c.minutes(1),nt=c.seconds(10),w={},k,T=new d("_modelenceCronJobs",{schema:{alias:a.String,lastStartDate:a.Date,lock:a.Object},indexes:[{key:{alias:1},unique:!0,background:!0}]});function st(e,{description:t="",interval:r,timeout:o=ot},n){if(w[e])throw new Error(`Duplicate cron job declaration: '${e}' already exists`);if(Se())throw new Error(`Unable to add a cron job - app has already been started: [${e}]`);if(k)throw new Error(`Unable to add a cron job - cron jobs have already been initialized: [${e}]`);if(r<c.seconds(5))throw new Error(`Cron job interval should not be less than 5 second [${e}]`);if(o>c.days(1))throw new Error(`Cron job timeout should not be longer than 1 day [${e}]`);w[e]={alias:e,params:{description:t,interval:r,timeout:o},handler:n,state:{isRunning:!1}};}async function Ee(){if(k)throw new Error("Cron jobs already started");let t={alias:{$in:Object.keys(w)}},r=await T.findOne({...t,"lock.containerId":{$exists:!0}});await T.upsertMany(t,{$set:{lock:{containerId:process.env.MODELENCE_CONTAINER_ID||"unknown",acquireDate:new Date}}}),r&&await it(nt);let o=await T.fetch(t),n=Date.now();o.forEach(s=>{let i=w[s.alias];i&&(i.state.scheduledRunTs=s.lastStartDate?s.lastStartDate.getTime()+i.params.interval:n);}),Object.values(w).forEach(s=>{s.state.scheduledRunTs||(s.state.scheduledRunTs=n);}),k=setInterval(at,c.seconds(1));}function it(e){return new Promise(t=>setTimeout(t,e))}async function at(){let e=Date.now();Object.values(w).forEach(async t=>{let{params:r,state:o}=t;if(o.isRunning){o.startTs&&o.startTs+r.timeout<e&&(o.isRunning=!1);return}o.scheduledRunTs&&o.scheduledRunTs<=e&&await ct(t);});}async function ct(e){let{alias:t,params:r,handler:o,state:n}=e;n.isRunning=!0,n.startTs=Date.now();let s=D("cron",`cron:${t}`);o().then(()=>{Te(n,r),s.end("success");}).catch(i=>{Te(n,r),Q(i),s.end("error"),console.error(`Error in cron job '${t}':`,i);}),await T.updateOne({alias:t},{$set:{lastStartDate:new Date(n.startTs)}});}function Te(e,t){e.scheduledRunTs=e.startTs?e.startTs+t.interval:Date.now(),e.startTs=void 0,e.isRunning=!1;}function Me(){return Object.values(w).map(({alias:e,params:t})=>({alias:e,description:t.description,interval:t.interval,timeout:t.timeout}))}var De=new u("_system.cron",{stores:[T]});async function ut({configSchema:e,modules:t=[]}={}){let r=[ue,ne,De];xe(),lt.config(),mt(r),dt(t),F(e??{});let o=pt([...r,...t]),{mongodbUri:n,configs:s}=await he({configSchema:e,cronJobsMetadata:Me(),stores:o});E(s),await fe(n),ft(o),await V(),Ce(),Number(process.env.MODELENCE_CRON_INSTANCE)&&Ee().catch(console.error),await pe();}function dt(e){for(let t of e){for(let[r,o]of Object.entries(t.queries))N(`${t.name}.${r}`,o);for(let[r,o]of Object.entries(t.mutations))Y(`${t.name}.${r}`,o);}}function mt(e){for(let t of e){for(let[r,o]of Object.entries(t.queries))G(`${t.name}.${r}`,o);for(let[r,o]of Object.entries(t.mutations))Z(`${t.name}.${r}`,o);}}function pt(e){return e.flatMap(t=>t.stores)}async function ft(e){let t=ge();if(!t)throw new Error("Failed to provision stores: MongoDB client not initialized");for(let r of e)r.provision(t);}
|
|
3
|
+
export{u as Module,a as SchemaTypes,d as Store,N as createQuery,st as defineCronJob,b as getConfig,ut as startApp};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type ConfigType = 'text' | 'string' | 'number' | 'boolean' | 'secret';
|
|
2
|
+
type ConfigKey = string;
|
|
3
|
+
type ConfigParams = {
|
|
4
|
+
type: ConfigType;
|
|
5
|
+
default: ValueType<ConfigType>;
|
|
6
|
+
isPublic: boolean;
|
|
7
|
+
};
|
|
8
|
+
type ConfigSchema = {
|
|
9
|
+
[key: string]: ConfigParams;
|
|
10
|
+
};
|
|
11
|
+
type ValueType<T> = T extends 'number' ? number : T extends 'string' ? string : T extends 'text' ? string : T extends 'boolean' ? boolean : T extends 'secret' ? string : never;
|
|
12
|
+
|
|
13
|
+
export type { ConfigKey as C, ConfigSchema as a };
|
package/index.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"name": "modelence",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Full-stack JavaScript platform for startups",
|
|
6
|
+
"main": "index.ts",
|
|
7
|
+
"types": "index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./index.ts",
|
|
10
|
+
"./client": "./client.ts",
|
|
11
|
+
"./server": "./server.ts"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"main": "dist/index.js",
|
|
23
|
+
"types": "dist/index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": "./dist/index.js",
|
|
26
|
+
"./client": "./dist/client.js",
|
|
27
|
+
"./server": "./dist/server.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/modelence/modelence.git"
|
|
33
|
+
},
|
|
34
|
+
"author": "Modelence",
|
|
35
|
+
"license": "UNLICENSED",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/modelence/modelence/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://modelence.com",
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/bcrypt": "^5.0.2",
|
|
42
|
+
"@types/express": "^5.0.0",
|
|
43
|
+
"@types/node": "^22.5.1",
|
|
44
|
+
"@types/react": "^18.3.5",
|
|
45
|
+
"@types/react-dom": "^19.0.1",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^8.17.0",
|
|
47
|
+
"@typescript-eslint/parser": "^8.17.0",
|
|
48
|
+
"tsup": "^8.3.5",
|
|
49
|
+
"typescript": "^5.7.2"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@aws-sdk/client-amp": "^3.665.0",
|
|
53
|
+
"@aws-sdk/client-sts": "^3.665.0",
|
|
54
|
+
"@aws-sdk/types": "^3.664.0",
|
|
55
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
56
|
+
"aws-sigv4-fetch": "^4.0.1",
|
|
57
|
+
"bcrypt": "^5.1.1",
|
|
58
|
+
"dotenv": "^16.4.5",
|
|
59
|
+
"elastic-apm-node": "^4.8.0",
|
|
60
|
+
"express": "^4.21.0",
|
|
61
|
+
"mongodb": "^6.8.1",
|
|
62
|
+
"react-router-dom": "^7.0.1",
|
|
63
|
+
"vite": "^6.0.3",
|
|
64
|
+
"vite-plugin-eslint": "^1.8.1",
|
|
65
|
+
"winston": "^3.15.0",
|
|
66
|
+
"winston-elasticsearch": "^0.19.0",
|
|
67
|
+
"zod": "^3.23.8"
|
|
68
|
+
}
|
|
69
|
+
}
|