@arcote.tech/arc-host 0.3.4 → 0.4.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.
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1024 -384
- package/dist/index.js.map +12 -8
- package/dist/src/connection-manager.d.ts +16 -1
- package/dist/src/connection-manager.d.ts.map +1 -1
- package/dist/src/context-handler.d.ts +3 -5
- package/dist/src/context-handler.d.ts.map +1 -1
- package/dist/src/create-server.d.ts +36 -0
- package/dist/src/create-server.d.ts.map +1 -0
- package/dist/src/cron-scheduler.d.ts +30 -0
- package/dist/src/cron-scheduler.d.ts.map +1 -0
- package/dist/src/event-auth.d.ts +6 -1
- package/dist/src/event-auth.d.ts.map +1 -1
- package/dist/src/index.d.ts +6 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/middleware/http.d.ts +15 -0
- package/dist/src/middleware/http.d.ts.map +1 -0
- package/dist/src/middleware/index.d.ts +4 -0
- package/dist/src/middleware/index.d.ts.map +1 -0
- package/dist/src/middleware/types.d.ts +31 -0
- package/dist/src/middleware/types.d.ts.map +1 -0
- package/dist/src/middleware/ws.d.ts +9 -0
- package/dist/src/middleware/ws.d.ts.map +1 -0
- package/dist/src/types.d.ts +25 -4
- package/dist/src/types.d.ts.map +1 -1
- package/index.ts +2 -4
- package/package.json +2 -1
- package/src/connection-manager.ts +37 -7
- package/src/context-handler.ts +22 -23
- package/src/create-server.ts +213 -0
- package/src/cron-scheduler.ts +124 -0
- package/src/event-auth.ts +26 -1
- package/src/index.ts +39 -9
- package/src/middleware/http.ts +414 -0
- package/src/middleware/index.ts +27 -0
- package/src/middleware/types.ts +42 -0
- package/src/middleware/ws.ts +266 -0
- package/src/types.ts +22 -4
- package/dist/src/arc-host.d.ts +0 -81
- package/dist/src/arc-host.d.ts.map +0 -1
- package/src/arc-host.ts +0 -858
package/dist/index.js
CHANGED
|
@@ -3673,20 +3673,18 @@ var require_jsonwebtoken = __commonJS((exports, module) => {
|
|
|
3673
3673
|
};
|
|
3674
3674
|
});
|
|
3675
3675
|
|
|
3676
|
-
// src/
|
|
3676
|
+
// src/create-server.ts
|
|
3677
3677
|
var import_jsonwebtoken = __toESM(require_jsonwebtoken(), 1);
|
|
3678
|
-
import { liveQuery } from "@arcote.tech/arc";
|
|
3679
3678
|
|
|
3680
3679
|
// src/connection-manager.ts
|
|
3681
3680
|
class ConnectionManager {
|
|
3682
3681
|
clients = new Map;
|
|
3683
3682
|
clientIdCounter = 0;
|
|
3684
|
-
addClient(ws
|
|
3683
|
+
addClient(ws) {
|
|
3685
3684
|
const clientId = `client_${++this.clientIdCounter}_${Date.now()}`;
|
|
3686
3685
|
const client = {
|
|
3687
3686
|
id: clientId,
|
|
3688
|
-
|
|
3689
|
-
rawToken,
|
|
3687
|
+
scopeTokens: new Map,
|
|
3690
3688
|
lastHostEventId: null,
|
|
3691
3689
|
ws
|
|
3692
3690
|
};
|
|
@@ -3706,6 +3704,22 @@ class ConnectionManager {
|
|
|
3706
3704
|
return;
|
|
3707
3705
|
return this.clients.get(clientId);
|
|
3708
3706
|
}
|
|
3707
|
+
setScopeToken(clientId, scope, decoded, raw) {
|
|
3708
|
+
const client = this.clients.get(clientId);
|
|
3709
|
+
if (client) {
|
|
3710
|
+
client.scopeTokens.set(scope, { decoded, raw });
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
getScopeToken(clientId, scope) {
|
|
3714
|
+
const client = this.clients.get(clientId);
|
|
3715
|
+
return client?.scopeTokens.get(scope);
|
|
3716
|
+
}
|
|
3717
|
+
getAllScopeTokens(clientId) {
|
|
3718
|
+
const client = this.clients.get(clientId);
|
|
3719
|
+
if (!client)
|
|
3720
|
+
return [];
|
|
3721
|
+
return Array.from(client.scopeTokens.values()).map((v) => v.decoded);
|
|
3722
|
+
}
|
|
3709
3723
|
updateLastSyncedEventId(clientId, hostEventId) {
|
|
3710
3724
|
const client = this.clients.get(clientId);
|
|
3711
3725
|
if (client) {
|
|
@@ -3741,10 +3755,10 @@ class ConnectionManager {
|
|
|
3741
3755
|
|
|
3742
3756
|
// src/context-handler.ts
|
|
3743
3757
|
import {
|
|
3744
|
-
AuthAdapter,
|
|
3745
3758
|
LocalEventPublisher,
|
|
3746
3759
|
MasterDataStorage,
|
|
3747
3760
|
Model,
|
|
3761
|
+
ScopedModel,
|
|
3748
3762
|
mutationExecutor
|
|
3749
3763
|
} from "@arcote.tech/arc";
|
|
3750
3764
|
|
|
@@ -3812,6 +3826,17 @@ function filterEventsForToken(token, events, eventDefinitions) {
|
|
|
3812
3826
|
return canTokenReceiveEvent(token, eventDef, eventInstance);
|
|
3813
3827
|
});
|
|
3814
3828
|
}
|
|
3829
|
+
function filterEventsForTokens(tokens, events, eventDefinitions) {
|
|
3830
|
+
if (tokens.length === 0) {
|
|
3831
|
+
return filterEventsForToken(null, events, eventDefinitions);
|
|
3832
|
+
}
|
|
3833
|
+
return events.filter((eventInstance) => {
|
|
3834
|
+
const eventDef = eventDefinitions.get(eventInstance.type);
|
|
3835
|
+
if (!eventDef)
|
|
3836
|
+
return false;
|
|
3837
|
+
return tokens.some((token) => canTokenReceiveEvent(token, eventDef, eventInstance));
|
|
3838
|
+
});
|
|
3839
|
+
}
|
|
3815
3840
|
|
|
3816
3841
|
// src/context-handler.ts
|
|
3817
3842
|
class ContextHandler {
|
|
@@ -3819,7 +3844,6 @@ class ContextHandler {
|
|
|
3819
3844
|
model;
|
|
3820
3845
|
dataStorage;
|
|
3821
3846
|
eventPublisher;
|
|
3822
|
-
authAdapter;
|
|
3823
3847
|
eventDefinitions = new Map;
|
|
3824
3848
|
hostEventIdCounter = 0;
|
|
3825
3849
|
initialized = false;
|
|
@@ -3827,12 +3851,10 @@ class ContextHandler {
|
|
|
3827
3851
|
this.context = context;
|
|
3828
3852
|
this.dataStorage = new MasterDataStorage(dbAdapter);
|
|
3829
3853
|
this.eventPublisher = new LocalEventPublisher(this.dataStorage);
|
|
3830
|
-
this.authAdapter = new AuthAdapter;
|
|
3831
3854
|
this.model = new Model(context, {
|
|
3832
3855
|
adapters: {
|
|
3833
3856
|
dataStorage: this.dataStorage,
|
|
3834
|
-
eventPublisher: this.eventPublisher
|
|
3835
|
-
authAdapter: this.authAdapter
|
|
3857
|
+
eventPublisher: this.eventPublisher
|
|
3836
3858
|
},
|
|
3837
3859
|
environment: "server"
|
|
3838
3860
|
});
|
|
@@ -3849,21 +3871,26 @@ class ContextHandler {
|
|
|
3849
3871
|
this.initialized = true;
|
|
3850
3872
|
}
|
|
3851
3873
|
async executeCommand(commandName, params, rawToken) {
|
|
3852
|
-
const
|
|
3853
|
-
|
|
3874
|
+
const scoped = new ScopedModel(this.model, "request");
|
|
3875
|
+
if (rawToken)
|
|
3876
|
+
scoped.setToken(rawToken);
|
|
3877
|
+
const mutations = mutationExecutor(scoped);
|
|
3878
|
+
let command;
|
|
3879
|
+
if (commandName.includes(".")) {
|
|
3880
|
+
const [elementName, methodName] = commandName.split(".");
|
|
3881
|
+
const element = mutations[elementName];
|
|
3882
|
+
command = element?.[methodName];
|
|
3883
|
+
} else {
|
|
3884
|
+
command = mutations[commandName];
|
|
3885
|
+
}
|
|
3854
3886
|
if (!command) {
|
|
3855
3887
|
throw new Error(`Command '${commandName}' not found`);
|
|
3856
3888
|
}
|
|
3857
|
-
this.authAdapter.setToken(rawToken);
|
|
3858
3889
|
try {
|
|
3859
|
-
|
|
3890
|
+
const result = await command(params);
|
|
3891
|
+
return result;
|
|
3860
3892
|
} catch (error) {
|
|
3861
|
-
console.error(`[ARC] Command '${commandName}' failed
|
|
3862
|
-
console.error(`[ARC] Params:`, JSON.stringify(params, null, 2));
|
|
3863
|
-
console.error(`[ARC] Error:`, error);
|
|
3864
|
-
if (error instanceof Error) {
|
|
3865
|
-
console.error(`[ARC] Stack:`, error.stack);
|
|
3866
|
-
}
|
|
3893
|
+
console.error(`[ARC] Command '${commandName}' failed:`, error);
|
|
3867
3894
|
throw error;
|
|
3868
3895
|
}
|
|
3869
3896
|
}
|
|
@@ -3939,315 +3966,618 @@ class ContextHandler {
|
|
|
3939
3966
|
getEventDefinitions() {
|
|
3940
3967
|
return this.eventDefinitions;
|
|
3941
3968
|
}
|
|
3942
|
-
|
|
3943
|
-
this.
|
|
3969
|
+
getEventPublisher() {
|
|
3970
|
+
return this.eventPublisher;
|
|
3944
3971
|
}
|
|
3945
3972
|
}
|
|
3946
3973
|
|
|
3947
|
-
//
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
await this.contextHandler.init();
|
|
3966
|
-
this.setupServer();
|
|
3967
|
-
}
|
|
3968
|
-
verifyToken(token) {
|
|
3969
|
-
try {
|
|
3970
|
-
const decoded = import_jsonwebtoken.default.verify(token, this.jwtSecret);
|
|
3971
|
-
if (decoded.tokenName && !decoded.tokenType) {
|
|
3972
|
-
return {
|
|
3973
|
-
tokenType: decoded.tokenName,
|
|
3974
|
-
params: decoded.params || {},
|
|
3975
|
-
iat: decoded.iat,
|
|
3976
|
-
exp: decoded.exp
|
|
3977
|
-
};
|
|
3978
|
-
}
|
|
3979
|
-
return decoded;
|
|
3980
|
-
} catch {
|
|
3981
|
-
try {
|
|
3982
|
-
const parts = token.split(".");
|
|
3983
|
-
if (parts.length !== 3)
|
|
3984
|
-
return null;
|
|
3985
|
-
const payload = JSON.parse(atob(parts[1]));
|
|
3986
|
-
return {
|
|
3987
|
-
tokenType: payload.tokenName,
|
|
3988
|
-
params: payload.params || {},
|
|
3989
|
-
iat: payload.iat,
|
|
3990
|
-
exp: payload.exp
|
|
3991
|
-
};
|
|
3992
|
-
} catch {
|
|
3993
|
-
return null;
|
|
3994
|
-
}
|
|
3995
|
-
}
|
|
3974
|
+
// ../../node_modules/croner/dist/croner.js
|
|
3975
|
+
function h(n, t, e, r, s, i, a, l) {
|
|
3976
|
+
return h.fromTZ(h.tp(n, t, e, r, s, i, a), l);
|
|
3977
|
+
}
|
|
3978
|
+
h.fromTZISO = (n, t, e) => h.fromTZ(k(n, t), e);
|
|
3979
|
+
h.fromTZ = function(n, t) {
|
|
3980
|
+
let e = new Date(Date.UTC(n.y, n.m - 1, n.d, n.h, n.i, n.s)), r = D(n.tz, e), s = new Date(e.getTime() - r), i = D(n.tz, s);
|
|
3981
|
+
if (i - r === 0)
|
|
3982
|
+
return s;
|
|
3983
|
+
{
|
|
3984
|
+
let a = new Date(e.getTime() - i), l = D(n.tz, a);
|
|
3985
|
+
if (l - i === 0)
|
|
3986
|
+
return a;
|
|
3987
|
+
if (!t && l - i > 0)
|
|
3988
|
+
return a;
|
|
3989
|
+
if (t)
|
|
3990
|
+
throw new Error("Invalid date passed to fromTZ()");
|
|
3991
|
+
return s;
|
|
3996
3992
|
}
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
3993
|
+
};
|
|
3994
|
+
h.toTZ = function(n, t) {
|
|
3995
|
+
let e = n.toLocaleString("en-US", { timeZone: t }).replace(/[\u202f]/, " "), r = new Date(e);
|
|
3996
|
+
return { y: r.getFullYear(), m: r.getMonth() + 1, d: r.getDate(), h: r.getHours(), i: r.getMinutes(), s: r.getSeconds(), tz: t };
|
|
3997
|
+
};
|
|
3998
|
+
h.tp = (n, t, e, r, s, i, a) => ({ y: n, m: t, d: e, h: r, i: s, s: i, tz: a });
|
|
3999
|
+
function D(n, t = new Date) {
|
|
4000
|
+
let e = t.toLocaleString("en-US", { timeZone: n, timeZoneName: "shortOffset" }).split(" ").slice(-1)[0], r = t.toLocaleString("en-US").replace(/[\u202f]/, " ");
|
|
4001
|
+
return Date.parse(`${r} GMT`) - Date.parse(`${r} ${e}`);
|
|
4002
|
+
}
|
|
4003
|
+
function k(n, t) {
|
|
4004
|
+
let e = new Date(Date.parse(n));
|
|
4005
|
+
if (isNaN(e))
|
|
4006
|
+
throw new Error("minitz: Invalid ISO8601 passed to parser.");
|
|
4007
|
+
let r = n.substring(9);
|
|
4008
|
+
return n.includes("Z") || r.includes("-") || r.includes("+") ? h.tp(e.getUTCFullYear(), e.getUTCMonth() + 1, e.getUTCDate(), e.getUTCHours(), e.getUTCMinutes(), e.getUTCSeconds(), "Etc/UTC") : h.tp(e.getFullYear(), e.getMonth() + 1, e.getDate(), e.getHours(), e.getMinutes(), e.getSeconds(), t);
|
|
4009
|
+
}
|
|
4010
|
+
h.minitz = h;
|
|
4011
|
+
var b = 32;
|
|
4012
|
+
var p = 31 | b;
|
|
4013
|
+
var v = [1, 2, 4, 8, 16];
|
|
4014
|
+
var d = class {
|
|
4015
|
+
pattern;
|
|
4016
|
+
timezone;
|
|
4017
|
+
second;
|
|
4018
|
+
minute;
|
|
4019
|
+
hour;
|
|
4020
|
+
day;
|
|
4021
|
+
month;
|
|
4022
|
+
dayOfWeek;
|
|
4023
|
+
lastDayOfMonth;
|
|
4024
|
+
starDOM;
|
|
4025
|
+
starDOW;
|
|
4026
|
+
constructor(t, e) {
|
|
4027
|
+
this.pattern = t, this.timezone = e, this.second = Array(60).fill(0), this.minute = Array(60).fill(0), this.hour = Array(24).fill(0), this.day = Array(31).fill(0), this.month = Array(12).fill(0), this.dayOfWeek = Array(7).fill(0), this.lastDayOfMonth = false, this.starDOM = false, this.starDOW = false, this.parse();
|
|
4028
|
+
}
|
|
4029
|
+
parse() {
|
|
4030
|
+
if (!(typeof this.pattern == "string" || this.pattern instanceof String))
|
|
4031
|
+
throw new TypeError("CronPattern: Pattern has to be of type string.");
|
|
4032
|
+
this.pattern.indexOf("@") >= 0 && (this.pattern = this.handleNicknames(this.pattern).trim());
|
|
4033
|
+
let t = this.pattern.replace(/\s+/g, " ").split(" ");
|
|
4034
|
+
if (t.length < 5 || t.length > 6)
|
|
4035
|
+
throw new TypeError("CronPattern: invalid configuration format ('" + this.pattern + "'), exactly five or six space separated parts are required.");
|
|
4036
|
+
if (t.length === 5 && t.unshift("0"), t[3].indexOf("L") >= 0 && (t[3] = t[3].replace("L", ""), this.lastDayOfMonth = true), t[3] == "*" && (this.starDOM = true), t[4].length >= 3 && (t[4] = this.replaceAlphaMonths(t[4])), t[5].length >= 3 && (t[5] = this.replaceAlphaDays(t[5])), t[5] == "*" && (this.starDOW = true), this.pattern.indexOf("?") >= 0) {
|
|
4037
|
+
let e = new f(new Date, this.timezone).getDate(true);
|
|
4038
|
+
t[0] = t[0].replace("?", e.getSeconds().toString()), t[1] = t[1].replace("?", e.getMinutes().toString()), t[2] = t[2].replace("?", e.getHours().toString()), this.starDOM || (t[3] = t[3].replace("?", e.getDate().toString())), t[4] = t[4].replace("?", (e.getMonth() + 1).toString()), this.starDOW || (t[5] = t[5].replace("?", e.getDay().toString()));
|
|
4039
|
+
}
|
|
4040
|
+
this.throwAtIllegalCharacters(t), this.partToArray("second", t[0], 0, 1), this.partToArray("minute", t[1], 0, 1), this.partToArray("hour", t[2], 0, 1), this.partToArray("day", t[3], -1, 1), this.partToArray("month", t[4], -1, 1), this.partToArray("dayOfWeek", t[5], 0, p), this.dayOfWeek[7] && (this.dayOfWeek[0] = this.dayOfWeek[7]);
|
|
4041
|
+
}
|
|
4042
|
+
partToArray(t, e, r, s) {
|
|
4043
|
+
let i = this[t], a = t === "day" && this.lastDayOfMonth;
|
|
4044
|
+
if (e === "" && !a)
|
|
4045
|
+
throw new TypeError("CronPattern: configuration entry " + t + " (" + e + ") is empty, check for trailing spaces.");
|
|
4046
|
+
if (e === "*")
|
|
4047
|
+
return i.fill(s);
|
|
4048
|
+
let l = e.split(",");
|
|
4049
|
+
if (l.length > 1)
|
|
4050
|
+
for (let o = 0;o < l.length; o++)
|
|
4051
|
+
this.partToArray(t, l[o], r, s);
|
|
4052
|
+
else
|
|
4053
|
+
e.indexOf("-") !== -1 && e.indexOf("/") !== -1 ? this.handleRangeWithStepping(e, t, r, s) : e.indexOf("-") !== -1 ? this.handleRange(e, t, r, s) : e.indexOf("/") !== -1 ? this.handleStepping(e, t, r, s) : e !== "" && this.handleNumber(e, t, r, s);
|
|
4054
|
+
}
|
|
4055
|
+
throwAtIllegalCharacters(t) {
|
|
4056
|
+
for (let e = 0;e < t.length; e++)
|
|
4057
|
+
if ((e === 5 ? /[^/*0-9,\-#L]+/ : /[^/*0-9,-]+/).test(t[e]))
|
|
4058
|
+
throw new TypeError("CronPattern: configuration entry " + e + " (" + t[e] + ") contains illegal characters.");
|
|
4059
|
+
}
|
|
4060
|
+
handleNumber(t, e, r, s) {
|
|
4061
|
+
let i = this.extractNth(t, e), a = parseInt(i[0], 10) + r;
|
|
4062
|
+
if (isNaN(a))
|
|
4063
|
+
throw new TypeError("CronPattern: " + e + " is not a number: '" + t + "'");
|
|
4064
|
+
this.setPart(e, a, i[1] || s);
|
|
4065
|
+
}
|
|
4066
|
+
setPart(t, e, r) {
|
|
4067
|
+
if (!Object.prototype.hasOwnProperty.call(this, t))
|
|
4068
|
+
throw new TypeError("CronPattern: Invalid part specified: " + t);
|
|
4069
|
+
if (t === "dayOfWeek") {
|
|
4070
|
+
if (e === 7 && (e = 0), e < 0 || e > 6)
|
|
4071
|
+
throw new RangeError("CronPattern: Invalid value for dayOfWeek: " + e);
|
|
4072
|
+
this.setNthWeekdayOfMonth(e, r);
|
|
4001
4073
|
return;
|
|
4002
4074
|
}
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4075
|
+
if (t === "second" || t === "minute") {
|
|
4076
|
+
if (e < 0 || e >= 60)
|
|
4077
|
+
throw new RangeError("CronPattern: Invalid value for " + t + ": " + e);
|
|
4078
|
+
} else if (t === "hour") {
|
|
4079
|
+
if (e < 0 || e >= 24)
|
|
4080
|
+
throw new RangeError("CronPattern: Invalid value for " + t + ": " + e);
|
|
4081
|
+
} else if (t === "day") {
|
|
4082
|
+
if (e < 0 || e >= 31)
|
|
4083
|
+
throw new RangeError("CronPattern: Invalid value for " + t + ": " + e);
|
|
4084
|
+
} else if (t === "month" && (e < 0 || e >= 12))
|
|
4085
|
+
throw new RangeError("CronPattern: Invalid value for " + t + ": " + e);
|
|
4086
|
+
this[t][e] = r;
|
|
4087
|
+
}
|
|
4088
|
+
handleRangeWithStepping(t, e, r, s) {
|
|
4089
|
+
let i = this.extractNth(t, e), a = i[0].match(/^(\d+)-(\d+)\/(\d+)$/);
|
|
4090
|
+
if (a === null)
|
|
4091
|
+
throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '" + t + "'");
|
|
4092
|
+
let [, l, o, u] = a, c = parseInt(l, 10) + r, w = parseInt(o, 10) + r, C = parseInt(u, 10);
|
|
4093
|
+
if (isNaN(c))
|
|
4094
|
+
throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");
|
|
4095
|
+
if (isNaN(w))
|
|
4096
|
+
throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");
|
|
4097
|
+
if (isNaN(C))
|
|
4098
|
+
throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");
|
|
4099
|
+
if (C === 0)
|
|
4100
|
+
throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");
|
|
4101
|
+
if (C > this[e].length)
|
|
4102
|
+
throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part (" + this[e].length + ")");
|
|
4103
|
+
if (c > w)
|
|
4104
|
+
throw new TypeError("CronPattern: From value is larger than to value: '" + t + "'");
|
|
4105
|
+
for (let T = c;T <= w; T += C)
|
|
4106
|
+
this.setPart(e, T, i[1] || s);
|
|
4107
|
+
}
|
|
4108
|
+
extractNth(t, e) {
|
|
4109
|
+
let r = t, s;
|
|
4110
|
+
if (r.includes("#")) {
|
|
4111
|
+
if (e !== "dayOfWeek")
|
|
4112
|
+
throw new Error("CronPattern: nth (#) only allowed in day-of-week field");
|
|
4113
|
+
s = r.split("#")[1], r = r.split("#")[0];
|
|
4114
|
+
}
|
|
4115
|
+
return [r, s];
|
|
4116
|
+
}
|
|
4117
|
+
handleRange(t, e, r, s) {
|
|
4118
|
+
let i = this.extractNth(t, e), a = i[0].split("-");
|
|
4119
|
+
if (a.length !== 2)
|
|
4120
|
+
throw new TypeError("CronPattern: Syntax error, illegal range: '" + t + "'");
|
|
4121
|
+
let l = parseInt(a[0], 10) + r, o = parseInt(a[1], 10) + r;
|
|
4122
|
+
if (isNaN(l))
|
|
4123
|
+
throw new TypeError("CronPattern: Syntax error, illegal lower range (NaN)");
|
|
4124
|
+
if (isNaN(o))
|
|
4125
|
+
throw new TypeError("CronPattern: Syntax error, illegal upper range (NaN)");
|
|
4126
|
+
if (l > o)
|
|
4127
|
+
throw new TypeError("CronPattern: From value is larger than to value: '" + t + "'");
|
|
4128
|
+
for (let u = l;u <= o; u++)
|
|
4129
|
+
this.setPart(e, u, i[1] || s);
|
|
4130
|
+
}
|
|
4131
|
+
handleStepping(t, e, r, s) {
|
|
4132
|
+
let i = this.extractNth(t, e), a = i[0].split("/");
|
|
4133
|
+
if (a.length !== 2)
|
|
4134
|
+
throw new TypeError("CronPattern: Syntax error, illegal stepping: '" + t + "'");
|
|
4135
|
+
a[0] === "" && (a[0] = "*");
|
|
4136
|
+
let l = 0;
|
|
4137
|
+
a[0] !== "*" && (l = parseInt(a[0], 10) + r);
|
|
4138
|
+
let o = parseInt(a[1], 10);
|
|
4139
|
+
if (isNaN(o))
|
|
4140
|
+
throw new TypeError("CronPattern: Syntax error, illegal stepping: (NaN)");
|
|
4141
|
+
if (o === 0)
|
|
4142
|
+
throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");
|
|
4143
|
+
if (o > this[e].length)
|
|
4144
|
+
throw new TypeError("CronPattern: Syntax error, max steps for part is (" + this[e].length + ")");
|
|
4145
|
+
for (let u = l;u < this[e].length; u += o)
|
|
4146
|
+
this.setPart(e, u, i[1] || s);
|
|
4147
|
+
}
|
|
4148
|
+
replaceAlphaDays(t) {
|
|
4149
|
+
return t.replace(/-sun/gi, "-7").replace(/sun/gi, "0").replace(/mon/gi, "1").replace(/tue/gi, "2").replace(/wed/gi, "3").replace(/thu/gi, "4").replace(/fri/gi, "5").replace(/sat/gi, "6");
|
|
4150
|
+
}
|
|
4151
|
+
replaceAlphaMonths(t) {
|
|
4152
|
+
return t.replace(/jan/gi, "1").replace(/feb/gi, "2").replace(/mar/gi, "3").replace(/apr/gi, "4").replace(/may/gi, "5").replace(/jun/gi, "6").replace(/jul/gi, "7").replace(/aug/gi, "8").replace(/sep/gi, "9").replace(/oct/gi, "10").replace(/nov/gi, "11").replace(/dec/gi, "12");
|
|
4153
|
+
}
|
|
4154
|
+
handleNicknames(t) {
|
|
4155
|
+
let e = t.trim().toLowerCase();
|
|
4156
|
+
return e === "@yearly" || e === "@annually" ? "0 0 1 1 *" : e === "@monthly" ? "0 0 1 * *" : e === "@weekly" ? "0 0 * * 0" : e === "@daily" ? "0 0 * * *" : e === "@hourly" ? "0 * * * *" : t;
|
|
4157
|
+
}
|
|
4158
|
+
setNthWeekdayOfMonth(t, e) {
|
|
4159
|
+
if (typeof e != "number" && e === "L")
|
|
4160
|
+
this.dayOfWeek[t] = this.dayOfWeek[t] | b;
|
|
4161
|
+
else if (e === p)
|
|
4162
|
+
this.dayOfWeek[t] = p;
|
|
4163
|
+
else if (e < 6 && e > 0)
|
|
4164
|
+
this.dayOfWeek[t] = this.dayOfWeek[t] | v[e - 1];
|
|
4165
|
+
else
|
|
4166
|
+
throw new TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${e}, Type: ${typeof e}`);
|
|
4016
4167
|
}
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4168
|
+
};
|
|
4169
|
+
var O = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
4170
|
+
var m = [["month", "year", 0], ["day", "month", -1], ["hour", "day", 0], ["minute", "hour", 0], ["second", "minute", 0]];
|
|
4171
|
+
var f = class n {
|
|
4172
|
+
tz;
|
|
4173
|
+
ms;
|
|
4174
|
+
second;
|
|
4175
|
+
minute;
|
|
4176
|
+
hour;
|
|
4177
|
+
day;
|
|
4178
|
+
month;
|
|
4179
|
+
year;
|
|
4180
|
+
constructor(t, e) {
|
|
4181
|
+
if (this.tz = e, t && t instanceof Date)
|
|
4182
|
+
if (!isNaN(t))
|
|
4183
|
+
this.fromDate(t);
|
|
4184
|
+
else
|
|
4185
|
+
throw new TypeError("CronDate: Invalid date passed to CronDate constructor");
|
|
4186
|
+
else if (t === undefined)
|
|
4187
|
+
this.fromDate(new Date);
|
|
4188
|
+
else if (t && typeof t == "string")
|
|
4189
|
+
this.fromString(t);
|
|
4190
|
+
else if (t instanceof n)
|
|
4191
|
+
this.fromCronDate(t);
|
|
4192
|
+
else
|
|
4193
|
+
throw new TypeError("CronDate: Invalid type (" + typeof t + ") passed to CronDate constructor");
|
|
4194
|
+
}
|
|
4195
|
+
isNthWeekdayOfMonth(t, e, r, s) {
|
|
4196
|
+
let a = new Date(Date.UTC(t, e, r)).getUTCDay(), l = 0;
|
|
4197
|
+
for (let o = 1;o <= r; o++)
|
|
4198
|
+
new Date(Date.UTC(t, e, o)).getUTCDay() === a && l++;
|
|
4199
|
+
if (s & p && v[l - 1] & s)
|
|
4200
|
+
return true;
|
|
4201
|
+
if (s & b) {
|
|
4202
|
+
let o = new Date(Date.UTC(t, e + 1, 0)).getUTCDate();
|
|
4203
|
+
for (let u = r + 1;u <= o; u++)
|
|
4204
|
+
if (new Date(Date.UTC(t, e, u)).getUTCDay() === a)
|
|
4205
|
+
return false;
|
|
4206
|
+
return true;
|
|
4021
4207
|
}
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4208
|
+
return false;
|
|
4209
|
+
}
|
|
4210
|
+
fromDate(t) {
|
|
4211
|
+
if (this.tz !== undefined)
|
|
4212
|
+
if (typeof this.tz == "number")
|
|
4213
|
+
this.ms = t.getUTCMilliseconds(), this.second = t.getUTCSeconds(), this.minute = t.getUTCMinutes() + this.tz, this.hour = t.getUTCHours(), this.day = t.getUTCDate(), this.month = t.getUTCMonth(), this.year = t.getUTCFullYear(), this.apply();
|
|
4214
|
+
else {
|
|
4215
|
+
let e = h.toTZ(t, this.tz);
|
|
4216
|
+
this.ms = t.getMilliseconds(), this.second = e.s, this.minute = e.i, this.hour = e.h, this.day = e.d, this.month = e.m - 1, this.year = e.y;
|
|
4217
|
+
}
|
|
4218
|
+
else
|
|
4219
|
+
this.ms = t.getMilliseconds(), this.second = t.getSeconds(), this.minute = t.getMinutes(), this.hour = t.getHours(), this.day = t.getDate(), this.month = t.getMonth(), this.year = t.getFullYear();
|
|
4220
|
+
}
|
|
4221
|
+
fromCronDate(t) {
|
|
4222
|
+
this.tz = t.tz, this.year = t.year, this.month = t.month, this.day = t.day, this.hour = t.hour, this.minute = t.minute, this.second = t.second, this.ms = t.ms;
|
|
4223
|
+
}
|
|
4224
|
+
apply() {
|
|
4225
|
+
if (this.month > 11 || this.day > O[this.month] || this.hour > 59 || this.minute > 59 || this.second > 59 || this.hour < 0 || this.minute < 0 || this.second < 0) {
|
|
4226
|
+
let t = new Date(Date.UTC(this.year, this.month, this.day, this.hour, this.minute, this.second, this.ms));
|
|
4227
|
+
return this.ms = t.getUTCMilliseconds(), this.second = t.getUTCSeconds(), this.minute = t.getUTCMinutes(), this.hour = t.getUTCHours(), this.day = t.getUTCDate(), this.month = t.getUTCMonth(), this.year = t.getUTCFullYear(), true;
|
|
4228
|
+
} else
|
|
4229
|
+
return false;
|
|
4230
|
+
}
|
|
4231
|
+
fromString(t) {
|
|
4232
|
+
if (typeof this.tz == "number") {
|
|
4233
|
+
let e = h.fromTZISO(t);
|
|
4234
|
+
this.ms = e.getUTCMilliseconds(), this.second = e.getUTCSeconds(), this.minute = e.getUTCMinutes(), this.hour = e.getUTCHours(), this.day = e.getUTCDate(), this.month = e.getUTCMonth(), this.year = e.getUTCFullYear(), this.apply();
|
|
4235
|
+
} else
|
|
4236
|
+
return this.fromDate(h.fromTZISO(t, this.tz));
|
|
4237
|
+
}
|
|
4238
|
+
findNext(t, e, r, s) {
|
|
4239
|
+
let i = this[e], a;
|
|
4240
|
+
r.lastDayOfMonth && (this.month !== 1 ? a = O[this.month] : a = new Date(Date.UTC(this.year, this.month + 1, 0, 0, 0, 0, 0)).getUTCDate());
|
|
4241
|
+
let l = !r.starDOW && e == "day" ? new Date(Date.UTC(this.year, this.month, 1, 0, 0, 0, 0)).getUTCDay() : undefined;
|
|
4242
|
+
for (let o = this[e] + s;o < r[e].length; o++) {
|
|
4243
|
+
let u = r[e][o];
|
|
4244
|
+
if (e === "day" && r.lastDayOfMonth && o - s == a && (u = 1), e === "day" && !r.starDOW) {
|
|
4245
|
+
let c = r.dayOfWeek[(l + (o - s - 1)) % 7];
|
|
4246
|
+
if (c && c & p)
|
|
4247
|
+
c = this.isNthWeekdayOfMonth(this.year, this.month, o - s, c) ? 1 : 0;
|
|
4248
|
+
else if (c)
|
|
4249
|
+
throw new Error(`CronDate: Invalid value for dayOfWeek encountered. ${c}`);
|
|
4250
|
+
t.legacyMode && !r.starDOM ? u = u || c : u = u && c;
|
|
4251
|
+
}
|
|
4252
|
+
if (u)
|
|
4253
|
+
return this[e] = o - s, i !== this[e] ? 2 : 1;
|
|
4254
|
+
}
|
|
4255
|
+
return 3;
|
|
4256
|
+
}
|
|
4257
|
+
recurse(t, e, r) {
|
|
4258
|
+
let s = this.findNext(e, m[r][0], t, m[r][2]);
|
|
4259
|
+
if (s > 1) {
|
|
4260
|
+
let i = r + 1;
|
|
4261
|
+
for (;i < m.length; )
|
|
4262
|
+
this[m[i][0]] = -m[i][2], i++;
|
|
4263
|
+
if (s === 3)
|
|
4264
|
+
return this[m[r][1]]++, this[m[r][0]] = -m[r][2], this.apply(), this.recurse(t, e, 0);
|
|
4265
|
+
if (this.apply())
|
|
4266
|
+
return this.recurse(t, e, r - 1);
|
|
4267
|
+
}
|
|
4268
|
+
return r += 1, r >= m.length ? this : this.year >= 3000 ? null : this.recurse(t, e, r);
|
|
4269
|
+
}
|
|
4270
|
+
increment(t, e, r) {
|
|
4271
|
+
return this.second += e.interval !== undefined && e.interval > 1 && r ? e.interval : 1, this.ms = 0, this.apply(), this.recurse(t, e, 0);
|
|
4272
|
+
}
|
|
4273
|
+
getDate(t) {
|
|
4274
|
+
return t || this.tz === undefined ? new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.ms) : typeof this.tz == "number" ? new Date(Date.UTC(this.year, this.month, this.day, this.hour, this.minute - this.tz, this.second, this.ms)) : h.fromTZ(h.tp(this.year, this.month + 1, this.day, this.hour, this.minute, this.second, this.tz), false);
|
|
4275
|
+
}
|
|
4276
|
+
getTime() {
|
|
4277
|
+
return this.getDate(false).getTime();
|
|
4278
|
+
}
|
|
4279
|
+
};
|
|
4280
|
+
function N(n2) {
|
|
4281
|
+
if (n2 === undefined && (n2 = {}), delete n2.name, n2.legacyMode = n2.legacyMode === undefined ? true : n2.legacyMode, n2.paused = n2.paused === undefined ? false : n2.paused, n2.maxRuns = n2.maxRuns === undefined ? 1 / 0 : n2.maxRuns, n2.catch = n2.catch === undefined ? false : n2.catch, n2.interval = n2.interval === undefined ? 0 : parseInt(n2.interval.toString(), 10), n2.utcOffset = n2.utcOffset === undefined ? undefined : parseInt(n2.utcOffset.toString(), 10), n2.unref = n2.unref === undefined ? false : n2.unref, n2.startAt && (n2.startAt = new f(n2.startAt, n2.timezone)), n2.stopAt && (n2.stopAt = new f(n2.stopAt, n2.timezone)), n2.interval !== null) {
|
|
4282
|
+
if (isNaN(n2.interval))
|
|
4283
|
+
throw new Error("CronOptions: Supplied value for interval is not a number");
|
|
4284
|
+
if (n2.interval < 0)
|
|
4285
|
+
throw new Error("CronOptions: Supplied value for interval can not be negative");
|
|
4286
|
+
}
|
|
4287
|
+
if (n2.utcOffset !== undefined) {
|
|
4288
|
+
if (isNaN(n2.utcOffset))
|
|
4289
|
+
throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.");
|
|
4290
|
+
if (n2.utcOffset < -870 || n2.utcOffset > 870)
|
|
4291
|
+
throw new Error("CronOptions: utcOffset out of bounds.");
|
|
4292
|
+
if (n2.utcOffset !== undefined && n2.timezone)
|
|
4293
|
+
throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.");
|
|
4294
|
+
}
|
|
4295
|
+
if (n2.unref !== true && n2.unref !== false)
|
|
4296
|
+
throw new Error("CronOptions: Unref should be either true, false or undefined(false).");
|
|
4297
|
+
return n2;
|
|
4298
|
+
}
|
|
4299
|
+
function g(n2) {
|
|
4300
|
+
return Object.prototype.toString.call(n2) === "[object Function]" || typeof n2 == "function" || n2 instanceof Function;
|
|
4301
|
+
}
|
|
4302
|
+
function S(n2) {
|
|
4303
|
+
return g(n2);
|
|
4304
|
+
}
|
|
4305
|
+
function P(n2) {
|
|
4306
|
+
typeof Deno < "u" && typeof Deno.unrefTimer < "u" ? Deno.unrefTimer(n2) : n2 && typeof n2.unref < "u" && n2.unref();
|
|
4307
|
+
}
|
|
4308
|
+
var _ = 30 * 1000;
|
|
4309
|
+
var y = [];
|
|
4310
|
+
var R = class {
|
|
4311
|
+
name;
|
|
4312
|
+
options;
|
|
4313
|
+
_states;
|
|
4314
|
+
fn;
|
|
4315
|
+
constructor(t, e, r) {
|
|
4316
|
+
let s, i;
|
|
4317
|
+
if (g(e))
|
|
4318
|
+
i = e;
|
|
4319
|
+
else if (typeof e == "object")
|
|
4320
|
+
s = e;
|
|
4321
|
+
else if (e !== undefined)
|
|
4322
|
+
throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");
|
|
4323
|
+
if (g(r))
|
|
4324
|
+
i = r;
|
|
4325
|
+
else if (typeof r == "object")
|
|
4326
|
+
s = r;
|
|
4327
|
+
else if (r !== undefined)
|
|
4328
|
+
throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).");
|
|
4329
|
+
if (this.name = s?.name, this.options = N(s), this._states = { kill: false, blocking: false, previousRun: undefined, currentRun: undefined, once: undefined, currentTimeout: undefined, maxRuns: s ? s.maxRuns : undefined, paused: s ? s.paused : false, pattern: new d("* * * * *") }, t && (t instanceof Date || typeof t == "string" && t.indexOf(":") > 0) ? this._states.once = new f(t, this.options.timezone || this.options.utcOffset) : this._states.pattern = new d(t, this.options.timezone), this.name) {
|
|
4330
|
+
if (y.find((l) => l.name === this.name))
|
|
4331
|
+
throw new Error("Cron: Tried to initialize new named job '" + this.name + "', but name already taken.");
|
|
4332
|
+
y.push(this);
|
|
4333
|
+
}
|
|
4334
|
+
return i !== undefined && S(i) && (this.fn = i, this.schedule()), this;
|
|
4335
|
+
}
|
|
4336
|
+
nextRun(t) {
|
|
4337
|
+
let e = this._next(t);
|
|
4338
|
+
return e ? e.getDate(false) : null;
|
|
4339
|
+
}
|
|
4340
|
+
nextRuns(t, e) {
|
|
4341
|
+
this._states.maxRuns !== undefined && t > this._states.maxRuns && (t = this._states.maxRuns);
|
|
4342
|
+
let r = [], s = e || this._states.currentRun || undefined;
|
|
4343
|
+
for (;t-- && (s = this.nextRun(s)); )
|
|
4344
|
+
r.push(s);
|
|
4345
|
+
return r;
|
|
4346
|
+
}
|
|
4347
|
+
getPattern() {
|
|
4348
|
+
return this._states.pattern ? this._states.pattern.pattern : undefined;
|
|
4349
|
+
}
|
|
4350
|
+
isRunning() {
|
|
4351
|
+
let t = this.nextRun(this._states.currentRun), e = !this._states.paused, r = this.fn !== undefined, s = !this._states.kill;
|
|
4352
|
+
return e && r && s && t !== null;
|
|
4353
|
+
}
|
|
4354
|
+
isStopped() {
|
|
4355
|
+
return this._states.kill;
|
|
4356
|
+
}
|
|
4357
|
+
isBusy() {
|
|
4358
|
+
return this._states.blocking;
|
|
4359
|
+
}
|
|
4360
|
+
currentRun() {
|
|
4361
|
+
return this._states.currentRun ? this._states.currentRun.getDate() : null;
|
|
4362
|
+
}
|
|
4363
|
+
previousRun() {
|
|
4364
|
+
return this._states.previousRun ? this._states.previousRun.getDate() : null;
|
|
4365
|
+
}
|
|
4366
|
+
msToNext(t) {
|
|
4367
|
+
let e = this._next(t);
|
|
4368
|
+
return e ? t instanceof f || t instanceof Date ? e.getTime() - t.getTime() : e.getTime() - new f(t).getTime() : null;
|
|
4369
|
+
}
|
|
4370
|
+
stop() {
|
|
4371
|
+
this._states.kill = true, this._states.currentTimeout && clearTimeout(this._states.currentTimeout);
|
|
4372
|
+
let t = y.indexOf(this);
|
|
4373
|
+
t >= 0 && y.splice(t, 1);
|
|
4374
|
+
}
|
|
4375
|
+
pause() {
|
|
4376
|
+
return this._states.paused = true, !this._states.kill;
|
|
4377
|
+
}
|
|
4378
|
+
resume() {
|
|
4379
|
+
return this._states.paused = false, !this._states.kill;
|
|
4380
|
+
}
|
|
4381
|
+
schedule(t) {
|
|
4382
|
+
if (t && this.fn)
|
|
4383
|
+
throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.");
|
|
4384
|
+
t && (this.fn = t);
|
|
4385
|
+
let e = this.msToNext(), r = this.nextRun(this._states.currentRun);
|
|
4386
|
+
return e == null || isNaN(e) || r === null ? this : (e > _ && (e = _), this._states.currentTimeout = setTimeout(() => this._checkTrigger(r), e), this._states.currentTimeout && this.options.unref && P(this._states.currentTimeout), this);
|
|
4387
|
+
}
|
|
4388
|
+
async _trigger(t) {
|
|
4389
|
+
if (this._states.blocking = true, this._states.currentRun = new f(undefined, this.options.timezone || this.options.utcOffset), this.options.catch)
|
|
4390
|
+
try {
|
|
4391
|
+
this.fn !== undefined && await this.fn(this, this.options.context);
|
|
4392
|
+
} catch (e) {
|
|
4393
|
+
g(this.options.catch) && this.options.catch(e, this);
|
|
4032
4394
|
}
|
|
4395
|
+
else
|
|
4396
|
+
this.fn !== undefined && await this.fn(this, this.options.context);
|
|
4397
|
+
this._states.previousRun = new f(t, this.options.timezone || this.options.utcOffset), this._states.blocking = false;
|
|
4398
|
+
}
|
|
4399
|
+
async trigger() {
|
|
4400
|
+
await this._trigger();
|
|
4401
|
+
}
|
|
4402
|
+
runsLeft() {
|
|
4403
|
+
return this._states.maxRuns;
|
|
4404
|
+
}
|
|
4405
|
+
_checkTrigger(t) {
|
|
4406
|
+
let e = new Date, r = !this._states.paused && e.getTime() >= t.getTime(), s = this._states.blocking && this.options.protect;
|
|
4407
|
+
r && !s ? (this._states.maxRuns !== undefined && this._states.maxRuns--, this._trigger()) : r && s && g(this.options.protect) && setTimeout(() => this.options.protect(this), 0), this.schedule();
|
|
4408
|
+
}
|
|
4409
|
+
_next(t) {
|
|
4410
|
+
let e = !!(t || this._states.currentRun), r = false;
|
|
4411
|
+
!t && this.options.startAt && this.options.interval && ([t, e] = this._calculatePreviousRun(t, e), r = !t), t = new f(t, this.options.timezone || this.options.utcOffset), this.options.startAt && t && t.getTime() < this.options.startAt.getTime() && (t = this.options.startAt);
|
|
4412
|
+
let s = this._states.once || new f(t, this.options.timezone || this.options.utcOffset);
|
|
4413
|
+
return !r && s !== this._states.once && (s = s.increment(this._states.pattern, this.options, e)), this._states.once && this._states.once.getTime() <= t.getTime() || s === null || this._states.maxRuns !== undefined && this._states.maxRuns <= 0 || this._states.kill || this.options.stopAt && s.getTime() >= this.options.stopAt.getTime() ? null : s;
|
|
4414
|
+
}
|
|
4415
|
+
_calculatePreviousRun(t, e) {
|
|
4416
|
+
let r = new f(undefined, this.options.timezone || this.options.utcOffset), s = t;
|
|
4417
|
+
if (this.options.startAt.getTime() <= r.getTime()) {
|
|
4418
|
+
s = this.options.startAt;
|
|
4419
|
+
let i = s.getTime() + this.options.interval * 1000;
|
|
4420
|
+
for (;i <= r.getTime(); )
|
|
4421
|
+
s = new f(s, this.options.timezone || this.options.utcOffset).increment(this._states.pattern, this.options, true), i = s.getTime() + this.options.interval * 1000;
|
|
4422
|
+
e = true;
|
|
4033
4423
|
}
|
|
4034
|
-
|
|
4035
|
-
this.connectionManager.updateLastSyncedEventId(clientId, lastEvent.hostId);
|
|
4036
|
-
this.connectionManager.sendToClient(clientId, {
|
|
4037
|
-
type: "sync-complete",
|
|
4038
|
-
lastHostEventId: lastEvent.hostId
|
|
4039
|
-
});
|
|
4424
|
+
return s === null && (s = undefined), [s, e];
|
|
4040
4425
|
}
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4426
|
+
};
|
|
4427
|
+
|
|
4428
|
+
// src/cron-scheduler.ts
|
|
4429
|
+
class CronScheduler {
|
|
4430
|
+
jobs = [];
|
|
4431
|
+
contextHandler;
|
|
4432
|
+
constructor(contextHandler) {
|
|
4433
|
+
this.contextHandler = contextHandler;
|
|
4434
|
+
}
|
|
4435
|
+
start() {
|
|
4436
|
+
const context = this.contextHandler.context;
|
|
4437
|
+
const cronEntries = this.discoverCronMethods(context);
|
|
4438
|
+
if (cronEntries.length === 0)
|
|
4439
|
+
return;
|
|
4440
|
+
console.log(`[ARC:Cron] Discovered ${cronEntries.length} cron method(s):`);
|
|
4441
|
+
for (const entry of cronEntries) {
|
|
4442
|
+
console.log(`[ARC:Cron] ${entry.aggregateName}.${entry.methodName} \u2192 "${entry.cronExpression}"`);
|
|
4443
|
+
const task = new R(entry.cronExpression, async () => {
|
|
4444
|
+
await this.executeCronMethod(entry);
|
|
4058
4445
|
});
|
|
4446
|
+
this.jobs.push({ entry, task });
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4449
|
+
stop() {
|
|
4450
|
+
for (const job of this.jobs) {
|
|
4451
|
+
job.task.stop();
|
|
4452
|
+
}
|
|
4453
|
+
this.jobs = [];
|
|
4454
|
+
console.log("[ARC:Cron] All cron jobs stopped.");
|
|
4455
|
+
}
|
|
4456
|
+
discoverCronMethods(context) {
|
|
4457
|
+
const entries = [];
|
|
4458
|
+
for (const element of context.elements) {
|
|
4459
|
+
const ctor = element.ctor;
|
|
4460
|
+
if (ctor?.__aggregateCronMethods) {
|
|
4461
|
+
entries.push(...ctor.__aggregateCronMethods);
|
|
4462
|
+
}
|
|
4059
4463
|
}
|
|
4464
|
+
return entries;
|
|
4060
4465
|
}
|
|
4061
|
-
async
|
|
4466
|
+
async executeCronMethod(entry) {
|
|
4467
|
+
const commandName = `${entry.aggregateName}.${entry.methodName}`;
|
|
4062
4468
|
try {
|
|
4063
|
-
const
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4469
|
+
const dataStorage = this.contextHandler.getDataStorage();
|
|
4470
|
+
const store = dataStorage.getStore(entry.aggregateName);
|
|
4471
|
+
const instances = await store.find({});
|
|
4472
|
+
if (instances.length === 0) {
|
|
4473
|
+
console.log(`[ARC:Cron] ${commandName}: no instances found, skipping.`);
|
|
4474
|
+
return;
|
|
4475
|
+
}
|
|
4476
|
+
console.log(`[ARC:Cron] ${commandName}: executing for ${instances.length} instance(s)...`);
|
|
4477
|
+
for (const instance of instances) {
|
|
4478
|
+
try {
|
|
4479
|
+
await this.contextHandler.executeCommand(commandName, { _id: instance._id }, null);
|
|
4480
|
+
} catch (error) {
|
|
4481
|
+
console.error(`[ARC:Cron] ${commandName} failed for instance ${instance._id}:`, error);
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4069
4484
|
} catch (error) {
|
|
4070
|
-
|
|
4071
|
-
type: "command-result",
|
|
4072
|
-
requestId: message.requestId,
|
|
4073
|
-
error: error.message
|
|
4074
|
-
});
|
|
4485
|
+
console.error(`[ARC:Cron] ${commandName} failed:`, error);
|
|
4075
4486
|
}
|
|
4076
4487
|
}
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
}
|
|
4095
|
-
const authHeader = req.headers.get("Authorization");
|
|
4096
|
-
const token = authHeader?.replace("Bearer ", "") || url.searchParams.get("token");
|
|
4097
|
-
let tokenPayload = null;
|
|
4098
|
-
if (token) {
|
|
4099
|
-
tokenPayload = self.verifyToken(token);
|
|
4100
|
-
}
|
|
4101
|
-
if (url.pathname === "/ws" && req.headers.get("Upgrade") === "websocket") {
|
|
4102
|
-
if (server.upgrade(req, {
|
|
4103
|
-
data: {
|
|
4104
|
-
clientId: "",
|
|
4105
|
-
token: tokenPayload,
|
|
4106
|
-
rawToken: token
|
|
4107
|
-
}
|
|
4108
|
-
})) {
|
|
4109
|
-
return;
|
|
4110
|
-
}
|
|
4111
|
-
return new Response("WebSocket upgrade failed", {
|
|
4112
|
-
status: 500,
|
|
4113
|
-
headers: corsHeaders
|
|
4114
|
-
});
|
|
4115
|
-
}
|
|
4116
|
-
if (url.pathname === "/health") {
|
|
4117
|
-
return new Response(JSON.stringify({
|
|
4118
|
-
status: "ok",
|
|
4119
|
-
clients: self.connectionManager.clientCount
|
|
4120
|
-
}), {
|
|
4121
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4122
|
-
});
|
|
4123
|
-
}
|
|
4124
|
-
if (url.pathname.startsWith("/command/") && req.method === "POST") {
|
|
4125
|
-
return self.handleHttpCommand(req, url, corsHeaders, token);
|
|
4126
|
-
}
|
|
4127
|
-
if (url.pathname.startsWith("/query/") && req.method === "POST") {
|
|
4128
|
-
return self.handleHttpQuery(req, url, tokenPayload, corsHeaders, token);
|
|
4129
|
-
}
|
|
4130
|
-
if (url.pathname.startsWith("/stream/") && req.method === "GET") {
|
|
4131
|
-
return self.handleHttpStream(req, url, tokenPayload, corsHeaders, token);
|
|
4132
|
-
}
|
|
4133
|
-
if (url.pathname === "/sync/events" && req.method === "POST") {
|
|
4134
|
-
return self.handleHttpEventSync(req, tokenPayload, corsHeaders);
|
|
4135
|
-
}
|
|
4136
|
-
if (url.pathname.startsWith("/route/")) {
|
|
4137
|
-
return self.handleHttpRoute(req, url, tokenPayload, corsHeaders, token);
|
|
4138
|
-
}
|
|
4139
|
-
return new Response("Not Found", { status: 404, headers: corsHeaders });
|
|
4140
|
-
},
|
|
4141
|
-
websocket: {
|
|
4142
|
-
open(ws) {
|
|
4143
|
-
const tokenPayload = ws.data?.token || null;
|
|
4144
|
-
const rawToken = ws.data?.rawToken || null;
|
|
4145
|
-
const client = self.connectionManager.addClient(ws, tokenPayload, rawToken);
|
|
4146
|
-
console.log(`Client connected: ${client.id}`);
|
|
4147
|
-
},
|
|
4148
|
-
message(ws, messageStr) {
|
|
4149
|
-
try {
|
|
4150
|
-
const message = JSON.parse(messageStr);
|
|
4151
|
-
self.handleMessage(ws, message);
|
|
4152
|
-
} catch (error) {
|
|
4153
|
-
console.error("Failed to parse message:", error);
|
|
4154
|
-
self.sendError(ws, "Invalid message format");
|
|
4155
|
-
}
|
|
4156
|
-
},
|
|
4157
|
-
close(ws) {
|
|
4158
|
-
const client = self.connectionManager.getClientByWs(ws);
|
|
4159
|
-
if (client) {
|
|
4160
|
-
console.log(`Client disconnected: ${client.id}`);
|
|
4161
|
-
self.connectionManager.removeClient(client.id);
|
|
4162
|
-
}
|
|
4488
|
+
}
|
|
4489
|
+
|
|
4490
|
+
// src/middleware/http.ts
|
|
4491
|
+
import { ScopedModel as ScopedModel2 } from "@arcote.tech/arc";
|
|
4492
|
+
async function parseCommandParams(req) {
|
|
4493
|
+
const contentType = req.headers.get("Content-Type") || "";
|
|
4494
|
+
if (contentType.includes("multipart/form-data")) {
|
|
4495
|
+
const formData = await req.formData();
|
|
4496
|
+
const params = {};
|
|
4497
|
+
for (const [key, value] of formData.entries()) {
|
|
4498
|
+
if (typeof value === "object" && value !== null && "name" in value && "size" in value) {
|
|
4499
|
+
params[key] = value;
|
|
4500
|
+
} else {
|
|
4501
|
+
try {
|
|
4502
|
+
params[key] = JSON.parse(value);
|
|
4503
|
+
} catch {
|
|
4504
|
+
params[key] = value;
|
|
4163
4505
|
}
|
|
4164
4506
|
}
|
|
4165
|
-
}
|
|
4166
|
-
|
|
4507
|
+
}
|
|
4508
|
+
return params;
|
|
4167
4509
|
}
|
|
4168
|
-
|
|
4510
|
+
return await req.json();
|
|
4511
|
+
}
|
|
4512
|
+
function healthHandler(cm) {
|
|
4513
|
+
return (_req, url, ctx) => {
|
|
4514
|
+
if (url.pathname !== "/health")
|
|
4515
|
+
return null;
|
|
4516
|
+
return Response.json({ status: "ok", clients: cm.clientCount }, { headers: ctx.corsHeaders });
|
|
4517
|
+
};
|
|
4518
|
+
}
|
|
4519
|
+
function commandHandler(ch) {
|
|
4520
|
+
return async (req, url, ctx) => {
|
|
4521
|
+
if (!url.pathname.startsWith("/command/") || req.method !== "POST")
|
|
4522
|
+
return null;
|
|
4169
4523
|
const commandName = url.pathname.split("/command/")[1];
|
|
4170
4524
|
if (!commandName) {
|
|
4171
4525
|
return new Response("Invalid command path", {
|
|
4172
4526
|
status: 400,
|
|
4173
|
-
headers: corsHeaders
|
|
4527
|
+
headers: ctx.corsHeaders
|
|
4174
4528
|
});
|
|
4175
4529
|
}
|
|
4176
4530
|
try {
|
|
4177
|
-
const params = await
|
|
4178
|
-
const result = await
|
|
4179
|
-
return
|
|
4180
|
-
headers:
|
|
4531
|
+
const params = await parseCommandParams(req);
|
|
4532
|
+
const result = await ch.executeCommand(commandName, params, ctx.rawToken);
|
|
4533
|
+
return Response.json(result ?? { success: true }, {
|
|
4534
|
+
headers: ctx.corsHeaders
|
|
4181
4535
|
});
|
|
4182
4536
|
} catch (error) {
|
|
4183
|
-
console.error(`[ARC
|
|
4184
|
-
|
|
4185
|
-
console.error(`[ARC HTTP] Stack trace:`, error.stack);
|
|
4186
|
-
}
|
|
4187
|
-
return new Response(JSON.stringify({ error: error.message }), {
|
|
4188
|
-
status: 500,
|
|
4189
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4190
|
-
});
|
|
4537
|
+
console.error(`[ARC] Command '${commandName}' error:`, error);
|
|
4538
|
+
return Response.json({ error: error.message }, { status: 500, headers: ctx.corsHeaders });
|
|
4191
4539
|
}
|
|
4192
|
-
}
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
for (const [key, value] of formData.entries()) {
|
|
4199
|
-
if (typeof value === "object" && value !== null && "name" in value && "size" in value) {
|
|
4200
|
-
params[key] = value;
|
|
4201
|
-
} else {
|
|
4202
|
-
try {
|
|
4203
|
-
params[key] = JSON.parse(value);
|
|
4204
|
-
} catch {
|
|
4205
|
-
params[key] = value;
|
|
4206
|
-
}
|
|
4207
|
-
}
|
|
4208
|
-
}
|
|
4209
|
-
return params;
|
|
4210
|
-
}
|
|
4211
|
-
return await req.json();
|
|
4212
|
-
}
|
|
4213
|
-
async handleHttpQuery(req, url, _token, corsHeaders, rawToken) {
|
|
4540
|
+
};
|
|
4541
|
+
}
|
|
4542
|
+
function queryHandler(ch) {
|
|
4543
|
+
return async (req, url, ctx) => {
|
|
4544
|
+
if (!url.pathname.startsWith("/query/") || req.method !== "POST")
|
|
4545
|
+
return null;
|
|
4214
4546
|
const viewName = url.pathname.split("/query/")[1];
|
|
4215
4547
|
if (!viewName) {
|
|
4216
4548
|
return new Response("Invalid query path", {
|
|
4217
4549
|
status: 400,
|
|
4218
|
-
headers: corsHeaders
|
|
4550
|
+
headers: ctx.corsHeaders
|
|
4219
4551
|
});
|
|
4220
4552
|
}
|
|
4221
4553
|
try {
|
|
4222
4554
|
const params = await req.json();
|
|
4223
|
-
const viewElement =
|
|
4224
|
-
if (!viewElement
|
|
4225
|
-
return
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
const model = this.contextHandler.getModel();
|
|
4232
|
-
const adapters = model.getAdapters();
|
|
4233
|
-
const queryCtx = viewElement.queryContext(adapters);
|
|
4555
|
+
const viewElement = ch.getModel().context.get(viewName);
|
|
4556
|
+
if (!viewElement?.queryContext) {
|
|
4557
|
+
return Response.json({ error: "View not found" }, { status: 404, headers: ctx.corsHeaders });
|
|
4558
|
+
}
|
|
4559
|
+
const scoped = new ScopedModel2(ch.getModel(), "request");
|
|
4560
|
+
if (ctx.rawToken)
|
|
4561
|
+
scoped.setToken(ctx.rawToken);
|
|
4562
|
+
const queryCtx = viewElement.queryContext(scoped.getAdapters());
|
|
4234
4563
|
const result = await queryCtx.find(params);
|
|
4235
|
-
return
|
|
4236
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4237
|
-
});
|
|
4564
|
+
return Response.json(result, { headers: ctx.corsHeaders });
|
|
4238
4565
|
} catch (error) {
|
|
4239
|
-
return
|
|
4240
|
-
status: 500,
|
|
4241
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4242
|
-
});
|
|
4566
|
+
return Response.json({ error: error.message }, { status: 500, headers: ctx.corsHeaders });
|
|
4243
4567
|
}
|
|
4244
|
-
}
|
|
4245
|
-
|
|
4568
|
+
};
|
|
4569
|
+
}
|
|
4570
|
+
var streamIdCounter = 0;
|
|
4571
|
+
var streamConnections = new Map;
|
|
4572
|
+
function streamHandler(ch) {
|
|
4573
|
+
return (_req, url, ctx) => {
|
|
4574
|
+
if (!url.pathname.startsWith("/stream/") || _req.method !== "GET")
|
|
4575
|
+
return null;
|
|
4246
4576
|
const viewName = url.pathname.split("/stream/")[1];
|
|
4247
4577
|
if (!viewName) {
|
|
4248
4578
|
return new Response("Invalid stream path", {
|
|
4249
4579
|
status: 400,
|
|
4250
|
-
headers: corsHeaders
|
|
4580
|
+
headers: ctx.corsHeaders
|
|
4251
4581
|
});
|
|
4252
4582
|
}
|
|
4253
4583
|
const findOptions = {};
|
|
@@ -4258,7 +4588,7 @@ class ArcHost {
|
|
|
4258
4588
|
} catch {
|
|
4259
4589
|
return new Response("Invalid 'where' parameter", {
|
|
4260
4590
|
status: 400,
|
|
4261
|
-
headers: corsHeaders
|
|
4591
|
+
headers: ctx.corsHeaders
|
|
4262
4592
|
});
|
|
4263
4593
|
}
|
|
4264
4594
|
}
|
|
@@ -4269,92 +4599,81 @@ class ArcHost {
|
|
|
4269
4599
|
} catch {
|
|
4270
4600
|
return new Response("Invalid 'orderBy' parameter", {
|
|
4271
4601
|
status: 400,
|
|
4272
|
-
headers: corsHeaders
|
|
4602
|
+
headers: ctx.corsHeaders
|
|
4273
4603
|
});
|
|
4274
4604
|
}
|
|
4275
4605
|
}
|
|
4276
4606
|
const limitParam = url.searchParams.get("limit");
|
|
4277
|
-
if (limitParam)
|
|
4607
|
+
if (limitParam)
|
|
4278
4608
|
findOptions.limit = parseInt(limitParam, 10);
|
|
4279
|
-
}
|
|
4280
|
-
const
|
|
4281
|
-
const self = this;
|
|
4609
|
+
const streamId = `stream_${++streamIdCounter}_${Date.now()}`;
|
|
4610
|
+
const rawToken = ctx.rawToken;
|
|
4282
4611
|
const stream = new ReadableStream({
|
|
4283
4612
|
start(controller) {
|
|
4284
|
-
const
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
throw new Error(`View '${viewName}' not found`);
|
|
4290
|
-
}
|
|
4291
|
-
return view.find(findOptions);
|
|
4292
|
-
}, (data) => {
|
|
4293
|
-
const event = `data: ${JSON.stringify({ type: "data", data })}
|
|
4294
|
-
|
|
4295
|
-
`;
|
|
4613
|
+
const scoped = new ScopedModel2(ch.getModel(), "stream");
|
|
4614
|
+
if (rawToken)
|
|
4615
|
+
scoped.setToken(rawToken);
|
|
4616
|
+
const descriptor = { element: viewName, method: "find", args: [findOptions] };
|
|
4617
|
+
const sendData = async () => {
|
|
4296
4618
|
try {
|
|
4297
|
-
|
|
4619
|
+
const data = await scoped.callQuery(descriptor);
|
|
4620
|
+
controller.enqueue(new TextEncoder().encode(`data: ${JSON.stringify({ type: "data", data })}
|
|
4621
|
+
|
|
4622
|
+
`));
|
|
4298
4623
|
} catch {
|
|
4299
4624
|
unsubscribe();
|
|
4300
4625
|
}
|
|
4301
|
-
}
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
});
|
|
4307
|
-
const connectEvent = `data: ${JSON.stringify({ type: "connected", streamId })}
|
|
4626
|
+
};
|
|
4627
|
+
sendData();
|
|
4628
|
+
const unsubscribe = ch.getEventPublisher().subscribe("*", () => sendData());
|
|
4629
|
+
streamConnections.set(streamId, { id: streamId, controller, unsubscribe });
|
|
4630
|
+
controller.enqueue(new TextEncoder().encode(`data: ${JSON.stringify({ type: "connected", streamId })}
|
|
4308
4631
|
|
|
4309
|
-
|
|
4310
|
-
controller.enqueue(new TextEncoder().encode(connectEvent));
|
|
4632
|
+
`));
|
|
4311
4633
|
},
|
|
4312
4634
|
cancel() {
|
|
4313
|
-
const conn =
|
|
4635
|
+
const conn = streamConnections.get(streamId);
|
|
4314
4636
|
if (conn) {
|
|
4315
4637
|
conn.unsubscribe();
|
|
4316
|
-
|
|
4638
|
+
streamConnections.delete(streamId);
|
|
4317
4639
|
}
|
|
4318
4640
|
}
|
|
4319
4641
|
});
|
|
4320
4642
|
return new Response(stream, {
|
|
4321
4643
|
headers: {
|
|
4322
|
-
...corsHeaders,
|
|
4644
|
+
...ctx.corsHeaders,
|
|
4323
4645
|
"Content-Type": "text/event-stream",
|
|
4324
4646
|
"Cache-Control": "no-cache",
|
|
4325
4647
|
Connection: "keep-alive"
|
|
4326
4648
|
}
|
|
4327
4649
|
});
|
|
4328
|
-
}
|
|
4329
|
-
|
|
4650
|
+
};
|
|
4651
|
+
}
|
|
4652
|
+
function eventSyncHandler(ch) {
|
|
4653
|
+
return async (req, url, ctx) => {
|
|
4654
|
+
if (url.pathname !== "/sync/events" || req.method !== "POST")
|
|
4655
|
+
return null;
|
|
4330
4656
|
try {
|
|
4331
4657
|
const body = await req.json();
|
|
4332
4658
|
const events = body.events || [];
|
|
4333
|
-
const
|
|
4659
|
+
const persisted = await ch.persistEvents(events.map((e) => ({
|
|
4334
4660
|
localId: e.localId,
|
|
4335
4661
|
type: e.type,
|
|
4336
4662
|
payload: e.payload,
|
|
4337
4663
|
createdAt: e.createdAt
|
|
4338
|
-
})), "http-sync",
|
|
4339
|
-
return
|
|
4340
|
-
success: true,
|
|
4341
|
-
syncedIds: persistedEvents.map((e) => e.localId)
|
|
4342
|
-
}), {
|
|
4343
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4344
|
-
});
|
|
4664
|
+
})), "http-sync", ctx.tokenPayload);
|
|
4665
|
+
return Response.json({ success: true, syncedIds: persisted.map((e) => e.localId) }, { headers: ctx.corsHeaders });
|
|
4345
4666
|
} catch (error) {
|
|
4346
|
-
return
|
|
4347
|
-
success: false,
|
|
4348
|
-
error: error.message
|
|
4349
|
-
}), {
|
|
4350
|
-
status: 500,
|
|
4351
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4352
|
-
});
|
|
4667
|
+
return Response.json({ success: false, error: error.message }, { status: 500, headers: ctx.corsHeaders });
|
|
4353
4668
|
}
|
|
4354
|
-
}
|
|
4355
|
-
|
|
4669
|
+
};
|
|
4670
|
+
}
|
|
4671
|
+
function routeHandler(ch) {
|
|
4672
|
+
return async (req, url, ctx) => {
|
|
4673
|
+
if (!url.pathname.startsWith("/route/"))
|
|
4674
|
+
return null;
|
|
4356
4675
|
const method = req.method;
|
|
4357
|
-
const context =
|
|
4676
|
+
const context = ch.getModel().context;
|
|
4358
4677
|
let matchedRoute = null;
|
|
4359
4678
|
let routeParams = {};
|
|
4360
4679
|
for (const element of context.elements) {
|
|
@@ -4369,31 +4688,21 @@ class ArcHost {
|
|
|
4369
4688
|
}
|
|
4370
4689
|
}
|
|
4371
4690
|
if (!matchedRoute) {
|
|
4372
|
-
return
|
|
4373
|
-
status: 404,
|
|
4374
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4375
|
-
});
|
|
4691
|
+
return Response.json({ error: "Route not found" }, { status: 404, headers: ctx.corsHeaders });
|
|
4376
4692
|
}
|
|
4377
4693
|
const handler = matchedRoute.getHandler(method);
|
|
4378
4694
|
if (!handler) {
|
|
4379
|
-
return
|
|
4380
|
-
status: 405,
|
|
4381
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4382
|
-
});
|
|
4695
|
+
return Response.json({ error: `Method ${method} not allowed` }, { status: 405, headers: ctx.corsHeaders });
|
|
4383
4696
|
}
|
|
4384
4697
|
if (!matchedRoute.isPublic && matchedRoute.hasProtections) {
|
|
4385
|
-
if (!tokenPayload) {
|
|
4386
|
-
return
|
|
4387
|
-
status: 401,
|
|
4388
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4389
|
-
});
|
|
4698
|
+
if (!ctx.tokenPayload) {
|
|
4699
|
+
return Response.json({ error: "Unauthorized" }, { status: 401, headers: ctx.corsHeaders });
|
|
4390
4700
|
}
|
|
4391
|
-
this.contextHandler.setAuthToken(rawToken);
|
|
4392
4701
|
let isAuthorized = false;
|
|
4393
4702
|
for (const protection of matchedRoute.protections) {
|
|
4394
|
-
if (protection.token.name === tokenPayload.tokenType) {
|
|
4703
|
+
if (protection.token.name === ctx.tokenPayload.tokenType) {
|
|
4395
4704
|
const mockTokenInstance = {
|
|
4396
|
-
params: tokenPayload.params,
|
|
4705
|
+
params: ctx.tokenPayload.params,
|
|
4397
4706
|
getTokenDefinition: () => protection.token
|
|
4398
4707
|
};
|
|
4399
4708
|
const allowed = await protection.check(mockTokenInstance);
|
|
@@ -4404,68 +4713,399 @@ class ArcHost {
|
|
|
4404
4713
|
}
|
|
4405
4714
|
}
|
|
4406
4715
|
if (!isAuthorized) {
|
|
4407
|
-
return
|
|
4408
|
-
status: 403,
|
|
4409
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4410
|
-
});
|
|
4716
|
+
return Response.json({ error: "Forbidden" }, { status: 403, headers: ctx.corsHeaders });
|
|
4411
4717
|
}
|
|
4412
4718
|
} else if (!matchedRoute.isPublic && !matchedRoute.hasProtections) {
|
|
4413
|
-
if (!tokenPayload) {
|
|
4414
|
-
return
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
const routeContext = matchedRoute.buildContext(
|
|
4719
|
+
if (!ctx.tokenPayload) {
|
|
4720
|
+
return Response.json({ error: "Unauthorized" }, { status: 401, headers: ctx.corsHeaders });
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
const scoped = new ScopedModel2(ch.getModel(), "request");
|
|
4724
|
+
if (ctx.rawToken)
|
|
4725
|
+
scoped.setToken(ctx.rawToken);
|
|
4726
|
+
const authParams = ctx.tokenPayload ? {
|
|
4727
|
+
params: ctx.tokenPayload.params,
|
|
4728
|
+
tokenName: ctx.tokenPayload.tokenType
|
|
4729
|
+
} : undefined;
|
|
4730
|
+
const routeContext = matchedRoute.buildContext(scoped.getAdapters(), authParams);
|
|
4425
4731
|
try {
|
|
4426
4732
|
const response = await handler(routeContext, req, routeParams, url);
|
|
4427
4733
|
const newHeaders = new Headers(response.headers);
|
|
4428
|
-
for (const [key, value] of Object.entries(corsHeaders))
|
|
4734
|
+
for (const [key, value] of Object.entries(ctx.corsHeaders))
|
|
4429
4735
|
newHeaders.set(key, value);
|
|
4430
|
-
|
|
4431
|
-
return new Response(
|
|
4736
|
+
const body = response.status >= 300 && response.status < 400 ? null : response.body;
|
|
4737
|
+
return new Response(body, {
|
|
4432
4738
|
status: response.status,
|
|
4433
4739
|
statusText: response.statusText,
|
|
4434
4740
|
headers: newHeaders
|
|
4435
4741
|
});
|
|
4436
4742
|
} catch (error) {
|
|
4437
|
-
return
|
|
4438
|
-
status: 500,
|
|
4439
|
-
headers: { ...corsHeaders, "Content-Type": "application/json" }
|
|
4440
|
-
});
|
|
4743
|
+
return Response.json({ error: error.message }, { status: 500, headers: ctx.corsHeaders });
|
|
4441
4744
|
}
|
|
4745
|
+
};
|
|
4746
|
+
}
|
|
4747
|
+
function arcHttpHandlers(ch, cm) {
|
|
4748
|
+
return [
|
|
4749
|
+
healthHandler(cm),
|
|
4750
|
+
commandHandler(ch),
|
|
4751
|
+
queryHandler(ch),
|
|
4752
|
+
streamHandler(ch),
|
|
4753
|
+
eventSyncHandler(ch),
|
|
4754
|
+
routeHandler(ch)
|
|
4755
|
+
];
|
|
4756
|
+
}
|
|
4757
|
+
function cleanupStreams() {
|
|
4758
|
+
for (const conn of streamConnections.values())
|
|
4759
|
+
conn.unsubscribe();
|
|
4760
|
+
streamConnections.clear();
|
|
4761
|
+
}
|
|
4762
|
+
// src/middleware/ws.ts
|
|
4763
|
+
import { ScopedModel as ScopedModel3 } from "@arcote.tech/arc";
|
|
4764
|
+
var clientViewSubs = new Map;
|
|
4765
|
+
function cleanupClientSubs(clientId) {
|
|
4766
|
+
const subs = clientViewSubs.get(clientId);
|
|
4767
|
+
if (subs) {
|
|
4768
|
+
for (const unsub of subs.values())
|
|
4769
|
+
unsub();
|
|
4770
|
+
clientViewSubs.delete(clientId);
|
|
4442
4771
|
}
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4772
|
+
}
|
|
4773
|
+
function scopeAuthHandler() {
|
|
4774
|
+
return async (client, message, ctx) => {
|
|
4775
|
+
if (message.type !== "scope:auth")
|
|
4776
|
+
return false;
|
|
4777
|
+
const decoded = ctx.verifyToken(message.token);
|
|
4778
|
+
if (decoded) {
|
|
4779
|
+
ctx.connectionManager.setScopeToken(client.id, message.scope, decoded, message.token);
|
|
4780
|
+
}
|
|
4781
|
+
return true;
|
|
4782
|
+
};
|
|
4783
|
+
}
|
|
4784
|
+
function syncEventsHandler() {
|
|
4785
|
+
return async (client, message, ctx) => {
|
|
4786
|
+
if (message.type !== "sync-events")
|
|
4787
|
+
return false;
|
|
4788
|
+
const allTokens = ctx.connectionManager.getAllScopeTokens(client.id);
|
|
4789
|
+
const token = allTokens.length > 0 ? allTokens[0] : null;
|
|
4790
|
+
const persisted = await ctx.contextHandler.persistEvents(message.events, client.id, token);
|
|
4791
|
+
if (persisted.length === 0)
|
|
4792
|
+
return true;
|
|
4793
|
+
for (const c of ctx.connectionManager.getAllClients()) {
|
|
4794
|
+
if (c.id === client.id)
|
|
4795
|
+
continue;
|
|
4796
|
+
const clientTokens = ctx.connectionManager.getAllScopeTokens(c.id);
|
|
4797
|
+
const authorized = filterEventsForTokens(clientTokens, persisted, ctx.contextHandler.getEventDefinitions());
|
|
4798
|
+
if (authorized.length > 0) {
|
|
4799
|
+
ctx.connectionManager.sendToClient(c.id, {
|
|
4800
|
+
type: "events",
|
|
4801
|
+
events: authorized
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
}
|
|
4805
|
+
const last = persisted[persisted.length - 1];
|
|
4806
|
+
ctx.connectionManager.updateLastSyncedEventId(client.id, last.hostId);
|
|
4807
|
+
ctx.connectionManager.sendToClient(client.id, {
|
|
4808
|
+
type: "sync-complete",
|
|
4809
|
+
lastHostEventId: last.hostId
|
|
4810
|
+
});
|
|
4811
|
+
return true;
|
|
4812
|
+
};
|
|
4813
|
+
}
|
|
4814
|
+
function requestSyncHandler() {
|
|
4815
|
+
return async (client, message, ctx) => {
|
|
4816
|
+
if (message.type !== "request-sync")
|
|
4817
|
+
return false;
|
|
4818
|
+
const allTokens = ctx.connectionManager.getAllScopeTokens(client.id);
|
|
4819
|
+
const token = allTokens.length > 0 ? allTokens[0] : null;
|
|
4820
|
+
const events = await ctx.contextHandler.getEventsSince(message.lastHostEventId, token);
|
|
4821
|
+
ctx.connectionManager.sendToClient(client.id, {
|
|
4822
|
+
type: "events",
|
|
4823
|
+
events
|
|
4824
|
+
});
|
|
4825
|
+
if (events.length > 0) {
|
|
4826
|
+
const last = events[events.length - 1];
|
|
4827
|
+
ctx.connectionManager.updateLastSyncedEventId(client.id, last.hostId);
|
|
4828
|
+
ctx.connectionManager.sendToClient(client.id, {
|
|
4829
|
+
type: "sync-complete",
|
|
4830
|
+
lastHostEventId: last.hostId
|
|
4831
|
+
});
|
|
4832
|
+
} else {
|
|
4833
|
+
ctx.connectionManager.sendToClient(client.id, {
|
|
4834
|
+
type: "sync-complete",
|
|
4835
|
+
lastHostEventId: message.lastHostEventId || ""
|
|
4836
|
+
});
|
|
4837
|
+
}
|
|
4838
|
+
return true;
|
|
4839
|
+
};
|
|
4840
|
+
}
|
|
4841
|
+
function executeCommandHandler() {
|
|
4842
|
+
return async (client, message, ctx) => {
|
|
4843
|
+
if (message.type !== "execute-command")
|
|
4844
|
+
return false;
|
|
4845
|
+
let rawToken = null;
|
|
4846
|
+
if (client.scopeTokens.size > 0) {
|
|
4847
|
+
rawToken = client.scopeTokens.values().next().value.raw;
|
|
4848
|
+
}
|
|
4849
|
+
try {
|
|
4850
|
+
const result = await ctx.contextHandler.executeCommand(message.commandName, message.params, rawToken);
|
|
4851
|
+
ctx.connectionManager.sendToClient(client.id, {
|
|
4852
|
+
type: "command-result",
|
|
4853
|
+
requestId: message.requestId,
|
|
4854
|
+
result
|
|
4855
|
+
});
|
|
4856
|
+
} catch (error) {
|
|
4857
|
+
ctx.connectionManager.sendToClient(client.id, {
|
|
4858
|
+
type: "command-result",
|
|
4859
|
+
requestId: message.requestId,
|
|
4860
|
+
error: error.message
|
|
4861
|
+
});
|
|
4862
|
+
}
|
|
4863
|
+
return true;
|
|
4864
|
+
};
|
|
4865
|
+
}
|
|
4866
|
+
function querySubscriptionHandler() {
|
|
4867
|
+
return async (client, message, ctx) => {
|
|
4868
|
+
if (message.type === "subscribe-query") {
|
|
4869
|
+
const { subscriptionId, descriptor, scope } = message;
|
|
4870
|
+
const scopeToken = scope ? client.scopeTokens.get(scope) : null;
|
|
4871
|
+
let rawToken = scopeToken?.raw ?? null;
|
|
4872
|
+
if (!rawToken && client.scopeTokens.size > 0) {
|
|
4873
|
+
rawToken = client.scopeTokens.values().next().value.raw;
|
|
4874
|
+
}
|
|
4875
|
+
const scoped = new ScopedModel3(ctx.contextHandler.getModel(), scope ?? "default");
|
|
4876
|
+
if (rawToken)
|
|
4877
|
+
scoped.setToken(rawToken);
|
|
4878
|
+
let lastResultJson = "";
|
|
4879
|
+
const sendData = async () => {
|
|
4880
|
+
try {
|
|
4881
|
+
const data = await scoped.callQuery(descriptor);
|
|
4882
|
+
const json = JSON.stringify(data ?? null);
|
|
4883
|
+
if (json === lastResultJson)
|
|
4884
|
+
return;
|
|
4885
|
+
lastResultJson = json;
|
|
4886
|
+
ctx.connectionManager.sendToClient(client.id, {
|
|
4887
|
+
type: "query-data",
|
|
4888
|
+
subscriptionId,
|
|
4889
|
+
data: data ?? null
|
|
4890
|
+
});
|
|
4891
|
+
} catch (err) {
|
|
4892
|
+
console.error(`[Arc] Query subscription error:`, err);
|
|
4893
|
+
}
|
|
4894
|
+
};
|
|
4895
|
+
sendData();
|
|
4896
|
+
const element = ctx.contextHandler.getModel().context.get(descriptor.element);
|
|
4897
|
+
const eventTypes = element?.getElements?.()?.map((e) => e.name) ?? [];
|
|
4898
|
+
let debounceTimer;
|
|
4899
|
+
const debouncedSend = () => {
|
|
4900
|
+
if (debounceTimer)
|
|
4901
|
+
clearTimeout(debounceTimer);
|
|
4902
|
+
debounceTimer = setTimeout(() => sendData(), 50);
|
|
4903
|
+
};
|
|
4904
|
+
const unsubscribes = [];
|
|
4905
|
+
if (eventTypes.length > 0) {
|
|
4906
|
+
for (const eventType of eventTypes) {
|
|
4907
|
+
unsubscribes.push(ctx.contextHandler.getEventPublisher().subscribe(eventType, debouncedSend));
|
|
4908
|
+
}
|
|
4909
|
+
} else {
|
|
4910
|
+
unsubscribes.push(ctx.contextHandler.getEventPublisher().subscribe("*", debouncedSend));
|
|
4911
|
+
}
|
|
4912
|
+
const cleanup = () => {
|
|
4913
|
+
if (debounceTimer)
|
|
4914
|
+
clearTimeout(debounceTimer);
|
|
4915
|
+
for (const unsub of unsubscribes)
|
|
4916
|
+
unsub();
|
|
4917
|
+
};
|
|
4918
|
+
if (!clientViewSubs.has(client.id)) {
|
|
4919
|
+
clientViewSubs.set(client.id, new Map);
|
|
4920
|
+
}
|
|
4921
|
+
clientViewSubs.get(client.id).set(subscriptionId, cleanup);
|
|
4922
|
+
return true;
|
|
4923
|
+
}
|
|
4924
|
+
if (message.type === "unsubscribe-query") {
|
|
4925
|
+
const subs = clientViewSubs.get(client.id);
|
|
4926
|
+
if (subs) {
|
|
4927
|
+
const unsub = subs.get(message.subscriptionId);
|
|
4928
|
+
if (unsub) {
|
|
4929
|
+
unsub();
|
|
4930
|
+
subs.delete(message.subscriptionId);
|
|
4931
|
+
}
|
|
4932
|
+
}
|
|
4933
|
+
return true;
|
|
4934
|
+
}
|
|
4935
|
+
return false;
|
|
4936
|
+
};
|
|
4937
|
+
}
|
|
4938
|
+
function arcWsHandlers() {
|
|
4939
|
+
return [
|
|
4940
|
+
scopeAuthHandler(),
|
|
4941
|
+
syncEventsHandler(),
|
|
4942
|
+
requestSyncHandler(),
|
|
4943
|
+
executeCommandHandler(),
|
|
4944
|
+
querySubscriptionHandler()
|
|
4945
|
+
];
|
|
4946
|
+
}
|
|
4947
|
+
// src/create-server.ts
|
|
4948
|
+
async function createArcServer(config) {
|
|
4949
|
+
const jwtSecret = config.jwtSecret || process.env.JWT_SECRET || "arc-host-secret-change-in-production";
|
|
4950
|
+
const port = config.port || 5005;
|
|
4951
|
+
const dbAdapter = config.dbAdapterFactory(config.context);
|
|
4952
|
+
const contextHandler = new ContextHandler(config.context, dbAdapter);
|
|
4953
|
+
await contextHandler.init();
|
|
4954
|
+
const cronScheduler = new CronScheduler(contextHandler);
|
|
4955
|
+
cronScheduler.start();
|
|
4956
|
+
const connectionManager = new ConnectionManager;
|
|
4957
|
+
const corsHeaders = {
|
|
4958
|
+
"Access-Control-Allow-Origin": "*",
|
|
4959
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
|
4960
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Arc-Scope"
|
|
4961
|
+
};
|
|
4962
|
+
function verifyToken(token) {
|
|
4963
|
+
try {
|
|
4964
|
+
const decoded = import_jsonwebtoken.default.verify(token, jwtSecret);
|
|
4965
|
+
if (decoded.tokenName && !decoded.tokenType) {
|
|
4966
|
+
return {
|
|
4967
|
+
tokenType: decoded.tokenName,
|
|
4968
|
+
params: decoded.params || {},
|
|
4969
|
+
iat: decoded.iat,
|
|
4970
|
+
exp: decoded.exp
|
|
4971
|
+
};
|
|
4972
|
+
}
|
|
4973
|
+
return decoded;
|
|
4974
|
+
} catch {
|
|
4975
|
+
try {
|
|
4976
|
+
const parts = token.split(".");
|
|
4977
|
+
if (parts.length !== 3)
|
|
4978
|
+
return null;
|
|
4979
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
4980
|
+
return {
|
|
4981
|
+
tokenType: payload.tokenName,
|
|
4982
|
+
params: payload.params || {},
|
|
4983
|
+
iat: payload.iat,
|
|
4984
|
+
exp: payload.exp
|
|
4985
|
+
};
|
|
4986
|
+
} catch {
|
|
4987
|
+
return null;
|
|
4988
|
+
}
|
|
4446
4989
|
}
|
|
4447
|
-
this.streamConnections.clear();
|
|
4448
|
-
this.server?.stop();
|
|
4449
4990
|
}
|
|
4991
|
+
const defaultHttp = arcHttpHandlers(contextHandler, connectionManager);
|
|
4992
|
+
const defaultWs = arcWsHandlers();
|
|
4993
|
+
const httpHandlers = config.httpHandlers ? [...defaultHttp, ...config.httpHandlers] : defaultHttp;
|
|
4994
|
+
const wsHandlers = config.wsHandlers ? [...defaultWs, ...config.wsHandlers] : defaultWs;
|
|
4995
|
+
const wsCtx = {
|
|
4996
|
+
contextHandler,
|
|
4997
|
+
connectionManager,
|
|
4998
|
+
verifyToken
|
|
4999
|
+
};
|
|
5000
|
+
const server = Bun.serve({
|
|
5001
|
+
port,
|
|
5002
|
+
idleTimeout: 255,
|
|
5003
|
+
async fetch(req, server2) {
|
|
5004
|
+
const url = new URL(req.url);
|
|
5005
|
+
if (req.method === "OPTIONS") {
|
|
5006
|
+
return new Response(null, { headers: corsHeaders });
|
|
5007
|
+
}
|
|
5008
|
+
const authHeader = req.headers.get("Authorization");
|
|
5009
|
+
const rawToken = authHeader?.replace("Bearer ", "") || url.searchParams.get("token");
|
|
5010
|
+
const tokenPayload = rawToken ? verifyToken(rawToken) : null;
|
|
5011
|
+
if (url.pathname === "/ws" && req.headers.get("Upgrade") === "websocket") {
|
|
5012
|
+
if (server2.upgrade(req, { data: { clientId: "" } }))
|
|
5013
|
+
return;
|
|
5014
|
+
return new Response("WebSocket upgrade failed", {
|
|
5015
|
+
status: 500,
|
|
5016
|
+
headers: corsHeaders
|
|
5017
|
+
});
|
|
5018
|
+
}
|
|
5019
|
+
const reqCtx = {
|
|
5020
|
+
rawToken,
|
|
5021
|
+
tokenPayload,
|
|
5022
|
+
corsHeaders
|
|
5023
|
+
};
|
|
5024
|
+
for (const handler of httpHandlers) {
|
|
5025
|
+
const response = await handler(req, url, reqCtx);
|
|
5026
|
+
if (response)
|
|
5027
|
+
return response;
|
|
5028
|
+
}
|
|
5029
|
+
return new Response("Not Found", {
|
|
5030
|
+
status: 404,
|
|
5031
|
+
headers: corsHeaders
|
|
5032
|
+
});
|
|
5033
|
+
},
|
|
5034
|
+
websocket: {
|
|
5035
|
+
open(ws) {
|
|
5036
|
+
connectionManager.addClient(ws);
|
|
5037
|
+
},
|
|
5038
|
+
async message(ws, messageStr) {
|
|
5039
|
+
const client = connectionManager.getClientByWs(ws);
|
|
5040
|
+
if (!client)
|
|
5041
|
+
return;
|
|
5042
|
+
try {
|
|
5043
|
+
const message = JSON.parse(messageStr);
|
|
5044
|
+
for (const handler of wsHandlers) {
|
|
5045
|
+
const handled = await handler(client, message, wsCtx);
|
|
5046
|
+
if (handled)
|
|
5047
|
+
break;
|
|
5048
|
+
}
|
|
5049
|
+
} catch (error) {
|
|
5050
|
+
console.error("Failed to parse WS message:", error);
|
|
5051
|
+
}
|
|
5052
|
+
},
|
|
5053
|
+
close(ws) {
|
|
5054
|
+
const client = connectionManager.getClientByWs(ws);
|
|
5055
|
+
if (client) {
|
|
5056
|
+
cleanupClientSubs(client.id);
|
|
5057
|
+
config.onWsClose?.(client.id);
|
|
5058
|
+
connectionManager.removeClient(client.id);
|
|
5059
|
+
}
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
});
|
|
5063
|
+
console.log(`Arc Server running on http://localhost:${port}`);
|
|
5064
|
+
return {
|
|
5065
|
+
server,
|
|
5066
|
+
contextHandler,
|
|
5067
|
+
connectionManager,
|
|
5068
|
+
cronScheduler,
|
|
5069
|
+
stop: () => {
|
|
5070
|
+
cronScheduler.stop();
|
|
5071
|
+
cleanupStreams();
|
|
5072
|
+
server.stop();
|
|
5073
|
+
}
|
|
5074
|
+
};
|
|
4450
5075
|
}
|
|
4451
5076
|
// index.ts
|
|
4452
5077
|
function hostLiveModel(context, dbAdapterFactory) {
|
|
4453
|
-
|
|
5078
|
+
return createArcServer({
|
|
4454
5079
|
context,
|
|
4455
5080
|
dbAdapterFactory
|
|
4456
5081
|
});
|
|
4457
|
-
host.start();
|
|
4458
|
-
return host;
|
|
4459
5082
|
}
|
|
4460
5083
|
export {
|
|
5084
|
+
syncEventsHandler,
|
|
5085
|
+
streamHandler,
|
|
5086
|
+
scopeAuthHandler,
|
|
5087
|
+
routeHandler,
|
|
5088
|
+
requestSyncHandler,
|
|
5089
|
+
querySubscriptionHandler,
|
|
5090
|
+
queryHandler,
|
|
4461
5091
|
hostLiveModel,
|
|
5092
|
+
healthHandler,
|
|
5093
|
+
filterEventsForTokens,
|
|
4462
5094
|
filterEventsForToken,
|
|
5095
|
+
executeCommandHandler,
|
|
5096
|
+
eventSyncHandler,
|
|
5097
|
+
createArcServer,
|
|
5098
|
+
commandHandler,
|
|
5099
|
+
cleanupStreams,
|
|
5100
|
+
cleanupClientSubs,
|
|
4463
5101
|
canTokenReceiveEvent,
|
|
4464
5102
|
canTokenEmitEvent,
|
|
5103
|
+
arcWsHandlers,
|
|
5104
|
+
arcHttpHandlers,
|
|
5105
|
+
CronScheduler,
|
|
4465
5106
|
ContextHandler,
|
|
4466
|
-
ConnectionManager
|
|
4467
|
-
ArcHost
|
|
5107
|
+
ConnectionManager
|
|
4468
5108
|
};
|
|
4469
5109
|
|
|
4470
|
-
//# debugId=
|
|
5110
|
+
//# debugId=8DE239ADA7ED79E164756E2164756E21
|
|
4471
5111
|
//# sourceMappingURL=index.js.map
|