@arcote.tech/arc 0.1.11 → 0.1.12
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/command/command-definition.d.ts +5 -0
- package/dist/context/event.d.ts +1 -0
- package/dist/context/index.d.ts +1 -0
- package/dist/context/translator.d.ts +4 -0
- package/dist/index.js +180 -130
- package/dist/model/EventPublisher.d.ts +12 -0
- package/dist/model/event-publisher.d.ts +12 -0
- package/dist/model/model.d.ts +13 -3
- package/dist/query/query-definition.d.ts +8 -0
- package/dist/server/query-handler.d.ts +43 -0
- package/dist/strategies/cache-strategy.d.ts +20 -0
- package/dist/strategies/datastorage-strategy.d.ts +15 -0
- package/dist/strategies/index.d.ts +7 -0
- package/dist/strategies/leader-strategy.d.ts +16 -0
- package/dist/strategies/model-strategy.d.ts +9 -0
- package/dist/strategies/query-strategy.d.ts +20 -0
- package/dist/view/query-builders/new-query-builder.d.ts +2 -0
- package/package.json +1 -1
package/dist/context/event.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export type ArcEventInstance<Event extends ArcEventAny> = {
|
|
|
31
31
|
payload: Event["payload"] extends ArcObjectAny ? $type<Event["payload"]> : undefined;
|
|
32
32
|
} & EventMetadata;
|
|
33
33
|
export type ArcEventAny = ArcEvent<any, any>;
|
|
34
|
+
export type ArcEventPayload<Event extends ArcEventAny> = Event extends ArcEvent<any, infer PayloadShape extends ArcObjectAny> ? $type<PayloadShape> : undefined;
|
|
34
35
|
export declare function event<const Name extends string, PayloadShape extends ArcObjectAny | ArcRawShape | undefined>(name: Name, payload?: PayloadShape): ArcEvent<Name, PayloadShape extends ArcRawShape ? ArcObject<PayloadShape, [{
|
|
35
36
|
name: "type";
|
|
36
37
|
validator: (value: any) => false | {
|
package/dist/context/index.d.ts
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ArcEventAny, ArcEventInstance, ArcEventPayload } from "./event";
|
|
2
|
+
export type Translation<From extends ArcEventAny, To extends ArcEventAny> = (event: ArcEventInstance<From>) => ArcEventPayload<To>;
|
|
3
|
+
export declare function translate<From extends ArcEventAny, To extends ArcEventAny>(from: From, to: To, translation: Translation<From, To>): import("..").ArcListener<`${From["name"]}To${To["name"]}Translator`, [To], [From]>;
|
|
4
|
+
//# sourceMappingURL=translator.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1621,14 +1621,16 @@ var sharedEventDatabaseSchema = null;
|
|
|
1621
1621
|
function getSharedEventDatabaseSchema() {
|
|
1622
1622
|
if (!sharedEventDatabaseSchema) {
|
|
1623
1623
|
sharedEventDatabaseSchema = {
|
|
1624
|
-
tables: [
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1624
|
+
tables: [
|
|
1625
|
+
{
|
|
1626
|
+
name: "events",
|
|
1627
|
+
schema: eventSchema,
|
|
1628
|
+
options: {
|
|
1629
|
+
softDelete: false,
|
|
1630
|
+
versioning: true
|
|
1631
|
+
}
|
|
1630
1632
|
}
|
|
1631
|
-
|
|
1633
|
+
]
|
|
1632
1634
|
};
|
|
1633
1635
|
}
|
|
1634
1636
|
return sharedEventDatabaseSchema;
|
|
@@ -1895,6 +1897,104 @@ class ReactiveQueryBuilder {
|
|
|
1895
1897
|
function reactive(fn) {
|
|
1896
1898
|
return (context2) => new ReactiveQueryBuilder(context2, fn);
|
|
1897
1899
|
}
|
|
1900
|
+
// listener/listener.ts
|
|
1901
|
+
class ArcListener extends ArcContextElement {
|
|
1902
|
+
name;
|
|
1903
|
+
_description;
|
|
1904
|
+
_elements;
|
|
1905
|
+
_eventElements;
|
|
1906
|
+
_handler;
|
|
1907
|
+
_isAsync = false;
|
|
1908
|
+
constructor(name) {
|
|
1909
|
+
super();
|
|
1910
|
+
this.name = name;
|
|
1911
|
+
}
|
|
1912
|
+
use(elements) {
|
|
1913
|
+
const clone = this.clone();
|
|
1914
|
+
clone._elements = elements;
|
|
1915
|
+
return clone;
|
|
1916
|
+
}
|
|
1917
|
+
description(description) {
|
|
1918
|
+
const clone = this.clone();
|
|
1919
|
+
clone._description = description;
|
|
1920
|
+
return clone;
|
|
1921
|
+
}
|
|
1922
|
+
listenTo(events) {
|
|
1923
|
+
const clone = this.clone();
|
|
1924
|
+
clone._eventElements = events;
|
|
1925
|
+
return clone;
|
|
1926
|
+
}
|
|
1927
|
+
async() {
|
|
1928
|
+
const clone = this.clone();
|
|
1929
|
+
clone._isAsync = true;
|
|
1930
|
+
return clone;
|
|
1931
|
+
}
|
|
1932
|
+
handle(handler) {
|
|
1933
|
+
const clone = this.clone();
|
|
1934
|
+
clone._handler = handler;
|
|
1935
|
+
return clone;
|
|
1936
|
+
}
|
|
1937
|
+
observer = (authContext) => {
|
|
1938
|
+
if (!this._handler || !this._elements || !this._eventElements) {
|
|
1939
|
+
return {};
|
|
1940
|
+
}
|
|
1941
|
+
const eventTypes = this._eventElements.filter((element2) => element2 instanceof ArcEvent).map((event2) => event2.name);
|
|
1942
|
+
return eventTypes.reduce((acc, eventType) => {
|
|
1943
|
+
acc[eventType] = {
|
|
1944
|
+
handler: async (event2, dataStorage, publishEvent) => {
|
|
1945
|
+
const ctx = new Proxy({}, {
|
|
1946
|
+
get: (target, name) => {
|
|
1947
|
+
if (name === "$auth") {
|
|
1948
|
+
return authContext;
|
|
1949
|
+
}
|
|
1950
|
+
if (name === "get") {
|
|
1951
|
+
return (e) => {
|
|
1952
|
+
const element3 = this._elements.find((element4) => element4.name === e.name);
|
|
1953
|
+
if (!element3) {
|
|
1954
|
+
throw new Error(`Element "${String(e.name)}" not found in listener "${this.name}"`);
|
|
1955
|
+
}
|
|
1956
|
+
if (!element3.commandContext) {
|
|
1957
|
+
throw new Error(`Element "${String(e.name)}" does not have a command context`);
|
|
1958
|
+
}
|
|
1959
|
+
return element3.commandContext(dataStorage, publishEvent, authContext);
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
const element2 = this._elements.find((element3) => element3.name === name);
|
|
1963
|
+
if (!element2) {
|
|
1964
|
+
throw new Error(`Element "${element2}" not found in listener "${this.name}"`);
|
|
1965
|
+
}
|
|
1966
|
+
if (!element2.commandContext) {
|
|
1967
|
+
throw new Error(`Element "${String(name)}" does not have a command context`);
|
|
1968
|
+
}
|
|
1969
|
+
return element2.commandContext(dataStorage, publishEvent, authContext);
|
|
1970
|
+
}
|
|
1971
|
+
});
|
|
1972
|
+
await this._handler(ctx, event2);
|
|
1973
|
+
},
|
|
1974
|
+
isAsync: this._isAsync
|
|
1975
|
+
};
|
|
1976
|
+
return acc;
|
|
1977
|
+
}, {});
|
|
1978
|
+
};
|
|
1979
|
+
clone() {
|
|
1980
|
+
const clone = new ArcListener(this.name);
|
|
1981
|
+
clone._description = this._description;
|
|
1982
|
+
clone._elements = this._elements;
|
|
1983
|
+
clone._eventElements = this._eventElements;
|
|
1984
|
+
clone._handler = this._handler;
|
|
1985
|
+
clone._isAsync = this._isAsync;
|
|
1986
|
+
return clone;
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
function listener(name) {
|
|
1990
|
+
return new ArcListener(name);
|
|
1991
|
+
}
|
|
1992
|
+
// context/translator.ts
|
|
1993
|
+
function translate(from, to, translation) {
|
|
1994
|
+
return listener(`${from.name}To${to.name}Translator`).listenTo([from]).use([to]).handle((ctx, event2) => {
|
|
1995
|
+
ctx.get(from).emit(translation(event2));
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1898
1998
|
// data-storage/data-storage.abstract.ts
|
|
1899
1999
|
class DataStorage {
|
|
1900
2000
|
async commitChanges(changes) {
|
|
@@ -1980,12 +2080,12 @@ class StoreState {
|
|
|
1980
2080
|
applySerializedChanges(changes) {
|
|
1981
2081
|
return Promise.all(changes.map((change) => this.applyChange(change)));
|
|
1982
2082
|
}
|
|
1983
|
-
unsubscribe(
|
|
1984
|
-
this.listeners.delete(
|
|
2083
|
+
unsubscribe(listener3) {
|
|
2084
|
+
this.listeners.delete(listener3);
|
|
1985
2085
|
}
|
|
1986
2086
|
notifyListeners(events) {
|
|
1987
|
-
for (const
|
|
1988
|
-
|
|
2087
|
+
for (const listener3 of this.listeners.values()) {
|
|
2088
|
+
listener3.callback(events);
|
|
1989
2089
|
}
|
|
1990
2090
|
}
|
|
1991
2091
|
}
|
|
@@ -2079,9 +2179,9 @@ class ForkedStoreState extends StoreState {
|
|
|
2079
2179
|
this.notifyListeners(events);
|
|
2080
2180
|
}
|
|
2081
2181
|
}
|
|
2082
|
-
async find(options,
|
|
2083
|
-
if (
|
|
2084
|
-
this.listeners.set(
|
|
2182
|
+
async find(options, listener3) {
|
|
2183
|
+
if (listener3) {
|
|
2184
|
+
this.listeners.set(listener3, { callback: listener3 });
|
|
2085
2185
|
}
|
|
2086
2186
|
const parentResults = await this.master.find(options);
|
|
2087
2187
|
const results = new Map;
|
|
@@ -2240,9 +2340,9 @@ class MasterStoreState extends StoreState {
|
|
|
2240
2340
|
this.notifyListeners(events);
|
|
2241
2341
|
}
|
|
2242
2342
|
}
|
|
2243
|
-
async find(options,
|
|
2244
|
-
if (
|
|
2245
|
-
this.listeners.set(
|
|
2343
|
+
async find(options, listener3) {
|
|
2344
|
+
if (listener3) {
|
|
2345
|
+
this.listeners.set(listener3, { callback: listener3 });
|
|
2246
2346
|
}
|
|
2247
2347
|
const transaction = await this.dataStorage.getReadTransaction();
|
|
2248
2348
|
const results = await transaction.find(this.storeName, options);
|
|
@@ -2470,7 +2570,7 @@ class PostgreSQLReadTransaction {
|
|
|
2470
2570
|
}
|
|
2471
2571
|
let query2 = `
|
|
2472
2572
|
SELECT *
|
|
2473
|
-
FROM "${
|
|
2573
|
+
FROM "${table.name}"
|
|
2474
2574
|
WHERE ${whereClause.sql}
|
|
2475
2575
|
${orderByClause}
|
|
2476
2576
|
`;
|
|
@@ -2502,7 +2602,7 @@ class PostgreSQLReadWriteTransaction extends PostgreSQLReadTransaction {
|
|
|
2502
2602
|
if (!table) {
|
|
2503
2603
|
throw new Error(`Store ${store} not found`);
|
|
2504
2604
|
}
|
|
2505
|
-
const query2 = `UPDATE "${
|
|
2605
|
+
const query2 = `UPDATE "${table.name}" SET "deleted" = $1, "lastUpdate" = $2 WHERE "${table.primaryKey}" = $3`;
|
|
2506
2606
|
this.queries.push({
|
|
2507
2607
|
sql: query2,
|
|
2508
2608
|
params: [true, new Date().toISOString(), id3]
|
|
@@ -3033,7 +3133,7 @@ class SQLiteReadTransaction {
|
|
|
3033
3133
|
}
|
|
3034
3134
|
const query2 = `
|
|
3035
3135
|
SELECT *
|
|
3036
|
-
FROM ${
|
|
3136
|
+
FROM ${table.name}
|
|
3037
3137
|
WHERE ${whereClause.sql}
|
|
3038
3138
|
${orderByClause}
|
|
3039
3139
|
${limit ? `LIMIT ${limit}` : ""}
|
|
@@ -3055,7 +3155,7 @@ class SQLiteReadWriteTransaction extends SQLiteReadTransaction {
|
|
|
3055
3155
|
if (!table) {
|
|
3056
3156
|
throw new Error(`Store ${store} not found`);
|
|
3057
3157
|
}
|
|
3058
|
-
const query2 = `UPDATE ${
|
|
3158
|
+
const query2 = `UPDATE ${table.name} SET deleted = 1, lastUpdate = ? WHERE ${table.primaryKey} = ?`;
|
|
3059
3159
|
await this.db.exec(query2, [new Date().toISOString(), id3]);
|
|
3060
3160
|
}
|
|
3061
3161
|
async set(store, item) {
|
|
@@ -3395,99 +3495,7 @@ var createSQLiteAdapterFactory = (db) => {
|
|
|
3395
3495
|
return adapter;
|
|
3396
3496
|
};
|
|
3397
3497
|
};
|
|
3398
|
-
//
|
|
3399
|
-
class ArcListener extends ArcContextElement {
|
|
3400
|
-
name;
|
|
3401
|
-
_description;
|
|
3402
|
-
_elements;
|
|
3403
|
-
_eventElements;
|
|
3404
|
-
_handler;
|
|
3405
|
-
_isAsync = false;
|
|
3406
|
-
constructor(name) {
|
|
3407
|
-
super();
|
|
3408
|
-
this.name = name;
|
|
3409
|
-
}
|
|
3410
|
-
use(elements) {
|
|
3411
|
-
const clone = this.clone();
|
|
3412
|
-
clone._elements = elements;
|
|
3413
|
-
return clone;
|
|
3414
|
-
}
|
|
3415
|
-
description(description) {
|
|
3416
|
-
const clone = this.clone();
|
|
3417
|
-
clone._description = description;
|
|
3418
|
-
return clone;
|
|
3419
|
-
}
|
|
3420
|
-
listenTo(events) {
|
|
3421
|
-
const clone = this.clone();
|
|
3422
|
-
clone._eventElements = events;
|
|
3423
|
-
return clone;
|
|
3424
|
-
}
|
|
3425
|
-
async() {
|
|
3426
|
-
const clone = this.clone();
|
|
3427
|
-
clone._isAsync = true;
|
|
3428
|
-
return clone;
|
|
3429
|
-
}
|
|
3430
|
-
handle(handler) {
|
|
3431
|
-
const clone = this.clone();
|
|
3432
|
-
clone._handler = handler;
|
|
3433
|
-
return clone;
|
|
3434
|
-
}
|
|
3435
|
-
observer = (authContext) => {
|
|
3436
|
-
if (!this._handler || !this._elements || !this._eventElements) {
|
|
3437
|
-
return {};
|
|
3438
|
-
}
|
|
3439
|
-
const eventTypes = this._eventElements.filter((element3) => element3 instanceof ArcEvent).map((event3) => event3.name);
|
|
3440
|
-
return eventTypes.reduce((acc, eventType) => {
|
|
3441
|
-
acc[eventType] = {
|
|
3442
|
-
handler: async (event3, dataStorage, publishEvent) => {
|
|
3443
|
-
const ctx = new Proxy({}, {
|
|
3444
|
-
get: (target, name) => {
|
|
3445
|
-
if (name === "$auth") {
|
|
3446
|
-
return authContext;
|
|
3447
|
-
}
|
|
3448
|
-
if (name === "get") {
|
|
3449
|
-
return (e) => {
|
|
3450
|
-
const element4 = this._elements.find((element5) => element5.name === e.name);
|
|
3451
|
-
if (!element4) {
|
|
3452
|
-
throw new Error(`Element "${String(e.name)}" not found in listener "${this.name}"`);
|
|
3453
|
-
}
|
|
3454
|
-
if (!element4.commandContext) {
|
|
3455
|
-
throw new Error(`Element "${String(e.name)}" does not have a command context`);
|
|
3456
|
-
}
|
|
3457
|
-
return element4.commandContext(dataStorage, publishEvent, authContext);
|
|
3458
|
-
};
|
|
3459
|
-
}
|
|
3460
|
-
const element3 = this._elements.find((element4) => element4.name === name);
|
|
3461
|
-
if (!element3) {
|
|
3462
|
-
throw new Error(`Element "${element3}" not found in listener "${this.name}"`);
|
|
3463
|
-
}
|
|
3464
|
-
if (!element3.commandContext) {
|
|
3465
|
-
throw new Error(`Element "${String(name)}" does not have a command context`);
|
|
3466
|
-
}
|
|
3467
|
-
return element3.commandContext(dataStorage, publishEvent, authContext);
|
|
3468
|
-
}
|
|
3469
|
-
});
|
|
3470
|
-
await this._handler(ctx, event3);
|
|
3471
|
-
},
|
|
3472
|
-
isAsync: this._isAsync
|
|
3473
|
-
};
|
|
3474
|
-
return acc;
|
|
3475
|
-
}, {});
|
|
3476
|
-
};
|
|
3477
|
-
clone() {
|
|
3478
|
-
const clone = new ArcListener(this.name);
|
|
3479
|
-
clone._description = this._description;
|
|
3480
|
-
clone._elements = this._elements;
|
|
3481
|
-
clone._eventElements = this._eventElements;
|
|
3482
|
-
clone._handler = this._handler;
|
|
3483
|
-
clone._isAsync = this._isAsync;
|
|
3484
|
-
return clone;
|
|
3485
|
-
}
|
|
3486
|
-
}
|
|
3487
|
-
function listener(name) {
|
|
3488
|
-
return new ArcListener(name);
|
|
3489
|
-
}
|
|
3490
|
-
// model/model.ts
|
|
3498
|
+
// model/event-publisher.ts
|
|
3491
3499
|
class EventPublisher {
|
|
3492
3500
|
context;
|
|
3493
3501
|
dataStorage;
|
|
@@ -3540,6 +3548,7 @@ class EventPublisher {
|
|
|
3540
3548
|
}
|
|
3541
3549
|
}
|
|
3542
3550
|
|
|
3551
|
+
// model/model.ts
|
|
3543
3552
|
class ModelBase {
|
|
3544
3553
|
token = null;
|
|
3545
3554
|
setAuthToken(token) {
|
|
@@ -3559,12 +3568,18 @@ class Model extends ModelBase {
|
|
|
3559
3568
|
this.catchErrorCallback = catchErrorCallback;
|
|
3560
3569
|
}
|
|
3561
3570
|
async query(queryBuilderFn, authContext) {
|
|
3571
|
+
if (!this.dataStorage) {
|
|
3572
|
+
throw new Error("DataStorage is required for query operations");
|
|
3573
|
+
}
|
|
3562
3574
|
const queryContext = new QueryBuilderContext(this.queryCache, this.dataStorage);
|
|
3563
3575
|
const queryBuilder = this.context.queryBuilder(queryContext, authContext);
|
|
3564
3576
|
const query2 = queryBuilderFn(queryBuilder).toQuery(queryContext);
|
|
3565
3577
|
return query2.run(this.dataStorage);
|
|
3566
3578
|
}
|
|
3567
3579
|
subscribe(queryBuilderFn, callback, authContext) {
|
|
3580
|
+
if (!this.dataStorage) {
|
|
3581
|
+
throw new Error("DataStorage is required for subscribe operations");
|
|
3582
|
+
}
|
|
3568
3583
|
const queryContext = new QueryBuilderContext(this.queryCache, this.dataStorage);
|
|
3569
3584
|
const queryBuilder = this.context.queryBuilder(queryContext, authContext);
|
|
3570
3585
|
const query2 = queryBuilderFn(queryBuilder).toQuery(queryContext);
|
|
@@ -3591,6 +3606,9 @@ class Model extends ModelBase {
|
|
|
3591
3606
|
throw new Error(`Element "${String(name)}" does not have a command client`);
|
|
3592
3607
|
}
|
|
3593
3608
|
return async (arg) => {
|
|
3609
|
+
if (!this.dataStorage) {
|
|
3610
|
+
throw new Error("DataStorage is required for command operations");
|
|
3611
|
+
}
|
|
3594
3612
|
const forkedDataStorage = this.dataStorage.fork();
|
|
3595
3613
|
const eventPublisher = new EventPublisher(this.context, this.dataStorage, authContext);
|
|
3596
3614
|
const publishEvent = async (event3) => {
|
|
@@ -3603,7 +3621,9 @@ class Model extends ModelBase {
|
|
|
3603
3621
|
eventPublisher.runAsyncListeners();
|
|
3604
3622
|
return result;
|
|
3605
3623
|
} catch (error) {
|
|
3606
|
-
this.catchErrorCallback
|
|
3624
|
+
if (this.catchErrorCallback) {
|
|
3625
|
+
this.catchErrorCallback(error);
|
|
3626
|
+
}
|
|
3607
3627
|
return error;
|
|
3608
3628
|
}
|
|
3609
3629
|
};
|
|
@@ -3625,6 +3645,9 @@ class Model extends ModelBase {
|
|
|
3625
3645
|
if (!handler) {
|
|
3626
3646
|
throw new Error(`Method ${method} not allowed for route ${String(name)}`);
|
|
3627
3647
|
}
|
|
3648
|
+
if (!this.dataStorage) {
|
|
3649
|
+
throw new Error("DataStorage is required for route operations");
|
|
3650
|
+
}
|
|
3628
3651
|
const forkedDataStorage = this.dataStorage.fork();
|
|
3629
3652
|
const eventPublisher = new EventPublisher(this.context, this.dataStorage, authContext);
|
|
3630
3653
|
const publishEvent = async (event3) => {
|
|
@@ -3637,7 +3660,9 @@ class Model extends ModelBase {
|
|
|
3637
3660
|
eventPublisher.runAsyncListeners();
|
|
3638
3661
|
return result;
|
|
3639
3662
|
} catch (error) {
|
|
3640
|
-
this.catchErrorCallback
|
|
3663
|
+
if (this.catchErrorCallback) {
|
|
3664
|
+
this.catchErrorCallback(error);
|
|
3665
|
+
}
|
|
3641
3666
|
throw error;
|
|
3642
3667
|
}
|
|
3643
3668
|
};
|
|
@@ -3654,6 +3679,8 @@ class RemoteModelClient extends ModelBase {
|
|
|
3654
3679
|
apiBaseUrl;
|
|
3655
3680
|
client;
|
|
3656
3681
|
catchErrorCallback;
|
|
3682
|
+
queryCache = new QueryCache;
|
|
3683
|
+
inFlightRequests = new Map;
|
|
3657
3684
|
constructor(context3, apiBaseUrl, client, catchErrorCallback) {
|
|
3658
3685
|
super();
|
|
3659
3686
|
this.context = context3;
|
|
@@ -3661,6 +3688,26 @@ class RemoteModelClient extends ModelBase {
|
|
|
3661
3688
|
this.client = client;
|
|
3662
3689
|
this.catchErrorCallback = catchErrorCallback;
|
|
3663
3690
|
}
|
|
3691
|
+
generateCacheKey(element3, queryType, params) {
|
|
3692
|
+
return `${element3}:${queryType}:${JSON.stringify(params)}`;
|
|
3693
|
+
}
|
|
3694
|
+
async executeQuery(queryTracking) {
|
|
3695
|
+
const response = await fetch(`${this.apiBaseUrl}/query`, {
|
|
3696
|
+
method: "POST",
|
|
3697
|
+
headers: this.getAuthHeaders(),
|
|
3698
|
+
body: JSON.stringify({
|
|
3699
|
+
query: {
|
|
3700
|
+
element: queryTracking.element,
|
|
3701
|
+
queryType: queryTracking.queryType,
|
|
3702
|
+
params: queryTracking.params
|
|
3703
|
+
}
|
|
3704
|
+
})
|
|
3705
|
+
});
|
|
3706
|
+
if (!response.ok) {
|
|
3707
|
+
throw new Error(`Query failed: ${response.statusText}`);
|
|
3708
|
+
}
|
|
3709
|
+
return await response.json();
|
|
3710
|
+
}
|
|
3664
3711
|
schemaContainsBlobOrFile(schema) {
|
|
3665
3712
|
if (!schema)
|
|
3666
3713
|
return false;
|
|
@@ -3778,21 +3825,23 @@ class RemoteModelClient extends ModelBase {
|
|
|
3778
3825
|
}
|
|
3779
3826
|
});
|
|
3780
3827
|
queryBuilderFn(queryBuilderProxy);
|
|
3781
|
-
const
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3828
|
+
const cacheKey = this.generateCacheKey(queryTracking.element, queryTracking.queryType, queryTracking.params);
|
|
3829
|
+
const cachedResult = this.queryCache.get([cacheKey]);
|
|
3830
|
+
if (cachedResult) {
|
|
3831
|
+
return cachedResult;
|
|
3832
|
+
}
|
|
3833
|
+
if (this.inFlightRequests.has(cacheKey)) {
|
|
3834
|
+
return this.inFlightRequests.get(cacheKey);
|
|
3835
|
+
}
|
|
3836
|
+
const requestPromise = this.executeQuery(queryTracking);
|
|
3837
|
+
this.inFlightRequests.set(cacheKey, requestPromise);
|
|
3838
|
+
try {
|
|
3839
|
+
const result = await requestPromise;
|
|
3840
|
+
this.queryCache.set([cacheKey], result);
|
|
3841
|
+
return result;
|
|
3842
|
+
} finally {
|
|
3843
|
+
this.inFlightRequests.delete(cacheKey);
|
|
3794
3844
|
}
|
|
3795
|
-
return await response.json();
|
|
3796
3845
|
}
|
|
3797
3846
|
subscribe(queryBuilderFn, callback, authContext) {
|
|
3798
3847
|
const result = this.query(queryBuilderFn, authContext);
|
|
@@ -4565,6 +4614,7 @@ function view(name, id3, schema) {
|
|
|
4565
4614
|
}
|
|
4566
4615
|
export {
|
|
4567
4616
|
view,
|
|
4617
|
+
translate,
|
|
4568
4618
|
stringEnum,
|
|
4569
4619
|
string,
|
|
4570
4620
|
staticView,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ArcContextAny, AuthContext } from "../context";
|
|
2
|
+
import type { DataStorage } from "../data-storage";
|
|
3
|
+
export declare class EventPublisher<C extends ArcContextAny> {
|
|
4
|
+
private readonly context;
|
|
5
|
+
private readonly dataStorage;
|
|
6
|
+
private readonly authContext;
|
|
7
|
+
private asyncEvents;
|
|
8
|
+
constructor(context: C, dataStorage: DataStorage, authContext: AuthContext);
|
|
9
|
+
publishEvent(event: any, commandDataStorage: DataStorage): Promise<void>;
|
|
10
|
+
runAsyncListeners(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=EventPublisher.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ArcContextAny, AuthContext } from "../context";
|
|
2
|
+
import type { DataStorage } from "../data-storage";
|
|
3
|
+
export declare class EventPublisher<C extends ArcContextAny> {
|
|
4
|
+
private readonly context;
|
|
5
|
+
private readonly dataStorage;
|
|
6
|
+
private readonly authContext;
|
|
7
|
+
private asyncEvents;
|
|
8
|
+
constructor(context: C, dataStorage: DataStorage, authContext: AuthContext);
|
|
9
|
+
publishEvent(event: any, commandDataStorage: DataStorage): Promise<void>;
|
|
10
|
+
runAsyncListeners(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=event-publisher.d.ts.map
|
package/dist/model/model.d.ts
CHANGED
|
@@ -19,10 +19,10 @@ export declare abstract class ModelBase<C extends ArcContextAny> {
|
|
|
19
19
|
}
|
|
20
20
|
export declare class Model<C extends ArcContextAny> extends ModelBase<C> {
|
|
21
21
|
private readonly context;
|
|
22
|
-
private readonly dataStorage
|
|
23
|
-
private readonly catchErrorCallback
|
|
22
|
+
private readonly dataStorage?;
|
|
23
|
+
private readonly catchErrorCallback?;
|
|
24
24
|
private queryCache;
|
|
25
|
-
constructor(context: C, dataStorage
|
|
25
|
+
constructor(context: C, dataStorage?: DataStorage | undefined, catchErrorCallback?: ((error: any) => void) | undefined);
|
|
26
26
|
query<Q extends IArcQueryBuilder>(queryBuilderFn: UnaryFunction<ReturnType<C["queryBuilder"]>, Q>, authContext: AuthContext): Promise<ReturnType<Q["toQuery"]>["lastResult"]>;
|
|
27
27
|
subscribe<Q extends IArcQueryBuilder>(queryBuilderFn: UnaryFunction<ReturnType<C["queryBuilder"]>, Q>, callback: (result: ReturnType<Q["toQuery"]>["lastResult"]) => void, authContext: AuthContext): {
|
|
28
28
|
result: ReturnType<Q["toQuery"]>["lastResult"];
|
|
@@ -37,7 +37,17 @@ export declare class RemoteModelClient<C extends ArcContextAny> extends ModelBas
|
|
|
37
37
|
private readonly apiBaseUrl;
|
|
38
38
|
private readonly client;
|
|
39
39
|
private readonly catchErrorCallback;
|
|
40
|
+
private queryCache;
|
|
41
|
+
private inFlightRequests;
|
|
40
42
|
constructor(context: C, apiBaseUrl: string, client: string, catchErrorCallback: (error: any) => void);
|
|
43
|
+
/**
|
|
44
|
+
* Generate a cache key from query details
|
|
45
|
+
*/
|
|
46
|
+
private generateCacheKey;
|
|
47
|
+
/**
|
|
48
|
+
* Execute the actual HTTP query request
|
|
49
|
+
*/
|
|
50
|
+
private executeQuery;
|
|
41
51
|
/**
|
|
42
52
|
* Check if a schema contains blob or file elements
|
|
43
53
|
*/
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type QueryDefinition<TResult = any> = {
|
|
2
|
+
readonly contextElementName: string;
|
|
3
|
+
readonly queryAlias: string;
|
|
4
|
+
readonly parameters: any[];
|
|
5
|
+
readonly restrictions?: any;
|
|
6
|
+
};
|
|
7
|
+
export type QueryDefinitionResult<QD extends QueryDefinition> = QD extends QueryDefinition<infer T> ? T : unknown;
|
|
8
|
+
//# sourceMappingURL=query-definition.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ArcContextAny } from "../context";
|
|
2
|
+
import type { AuthContext } from "../context/element";
|
|
3
|
+
import type { DataStorage } from "../data-storage";
|
|
4
|
+
import { QueryDefinition } from "../strategies";
|
|
5
|
+
export declare class QueryHandler<C extends ArcContextAny> {
|
|
6
|
+
private model;
|
|
7
|
+
constructor(context: C, dataStorage: DataStorage, catchErrorCallback?: (error: any) => void);
|
|
8
|
+
/**
|
|
9
|
+
* Handle HTTP query requests
|
|
10
|
+
*/
|
|
11
|
+
handleQuery(queryDefinition: QueryDefinition, authContext: AuthContext): Promise<any>;
|
|
12
|
+
/**
|
|
13
|
+
* Handle HTTP query requests with streaming for real-time updates
|
|
14
|
+
*/
|
|
15
|
+
handleQueryWithStream(queryDefinition: QueryDefinition, authContext: AuthContext, streamCallback: (result: any) => void): Promise<any>;
|
|
16
|
+
/**
|
|
17
|
+
* Handle query sync requests for cache strategy
|
|
18
|
+
*/
|
|
19
|
+
handleQuerySync(queryDefinition: QueryDefinition, authContext: AuthContext, syncData: {
|
|
20
|
+
id: string;
|
|
21
|
+
version?: string;
|
|
22
|
+
}[]): Promise<{
|
|
23
|
+
updates: any[];
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Helper function to create HTTP handlers for different frameworks
|
|
28
|
+
*/
|
|
29
|
+
export declare function createHttpQueryHandlers<C extends ArcContextAny>(context: C, dataStorage: DataStorage, catchErrorCallback?: (error: any) => void): {
|
|
30
|
+
/**
|
|
31
|
+
* Handle POST /query
|
|
32
|
+
*/
|
|
33
|
+
handleQueryRequest: (req: Request) => Promise<Response>;
|
|
34
|
+
/**
|
|
35
|
+
* Handle POST /query-stream/:streamId
|
|
36
|
+
*/
|
|
37
|
+
handleQueryStreamRequest: (req: Request, streamId: string) => Promise<Response>;
|
|
38
|
+
/**
|
|
39
|
+
* Handle POST /query-sync
|
|
40
|
+
*/
|
|
41
|
+
handleQuerySyncRequest: (req: Request) => Promise<Response>;
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=query-handler.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ArcContextAny } from "../context";
|
|
2
|
+
import type { AuthContext } from "../context/element";
|
|
3
|
+
import type { DataStorage } from "../data-storage";
|
|
4
|
+
import type { QueryDefinition } from "../query/query-definition";
|
|
5
|
+
import type { CommandDefinition } from "../command/command-definition";
|
|
6
|
+
import type { ModelStrategy } from "./model-strategy";
|
|
7
|
+
export declare class CacheStrategy<C extends ArcContextAny> implements ModelStrategy {
|
|
8
|
+
private readonly dataStorage;
|
|
9
|
+
private dataStorageStrategy;
|
|
10
|
+
private leaderStrategy;
|
|
11
|
+
constructor(context: C, dataStorage: DataStorage, apiBaseUrl: string);
|
|
12
|
+
setAuthToken(token: string | null): void;
|
|
13
|
+
query<TResult = any>(queryDefinition: QueryDefinition<TResult>, authContext: AuthContext, callback?: (result: TResult) => void): Promise<TResult>;
|
|
14
|
+
command(commandDefinition: CommandDefinition, authContext: AuthContext): Promise<any>;
|
|
15
|
+
private extractSyncData;
|
|
16
|
+
private syncWithLeader;
|
|
17
|
+
private updateCache;
|
|
18
|
+
private establishLiveUpdates;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=cache-strategy.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ArcContextAny } from "../context";
|
|
2
|
+
import type { AuthContext } from "../context/element";
|
|
3
|
+
import type { DataStorage } from "../data-storage";
|
|
4
|
+
import type { QueryDefinition } from "../query/query-definition";
|
|
5
|
+
import type { CommandDefinition } from "../command/command-definition";
|
|
6
|
+
import type { ModelStrategy } from "./model-strategy";
|
|
7
|
+
export declare class DataStorageStrategy<C extends ArcContextAny> implements ModelStrategy {
|
|
8
|
+
private readonly context;
|
|
9
|
+
readonly dataStorage: DataStorage;
|
|
10
|
+
private readonly catchErrorCallback?;
|
|
11
|
+
constructor(context: C, dataStorage: DataStorage, catchErrorCallback?: ((error: any) => void) | undefined);
|
|
12
|
+
query<TResult = any>(queryDefinition: QueryDefinition<TResult>, authContext: AuthContext, callback?: (result: TResult) => void): Promise<TResult>;
|
|
13
|
+
command(commandDefinition: CommandDefinition, authContext: AuthContext): Promise<any>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=datastorage-strategy.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./model-strategy";
|
|
2
|
+
export * from "./datastorage-strategy";
|
|
3
|
+
export * from "./leader-strategy";
|
|
4
|
+
export * from "./cache-strategy";
|
|
5
|
+
export type { QueryDefinition } from "../query/query-definition";
|
|
6
|
+
export type { CommandDefinition } from "../command/command-definition";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AuthContext } from "../context/element";
|
|
2
|
+
import type { QueryDefinition } from "../query/query-definition";
|
|
3
|
+
import type { CommandDefinition } from "../command/command-definition";
|
|
4
|
+
import type { ModelStrategy } from "./model-strategy";
|
|
5
|
+
export declare class LeaderStrategy implements ModelStrategy {
|
|
6
|
+
private readonly apiBaseUrl;
|
|
7
|
+
private token;
|
|
8
|
+
constructor(apiBaseUrl: string);
|
|
9
|
+
setAuthToken(token: string | null): void;
|
|
10
|
+
query<TResult = any>(queryDefinition: QueryDefinition<TResult>, authContext: AuthContext, callback?: (result: TResult) => void): Promise<TResult>;
|
|
11
|
+
private queryWithStream;
|
|
12
|
+
private readStream;
|
|
13
|
+
command(commandDefinition: CommandDefinition, authContext: AuthContext): Promise<any>;
|
|
14
|
+
private getAuthHeaders;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=leader-strategy.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AuthContext } from "../context/element";
|
|
2
|
+
import type { QueryDefinition } from "../query/query-definition";
|
|
3
|
+
import type { CommandDefinition } from "../command/command-definition";
|
|
4
|
+
export interface ModelStrategy {
|
|
5
|
+
query<TResult = any>(queryDefinition: QueryDefinition<TResult>, authContext: AuthContext, callback?: (result: TResult) => void): Promise<TResult>;
|
|
6
|
+
command(commandDefinition: CommandDefinition, authContext: AuthContext): Promise<any>;
|
|
7
|
+
setAuthToken?(token: string | null): void;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=model-strategy.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AuthContext } from "../context/element";
|
|
2
|
+
export interface QueryDefinition {
|
|
3
|
+
contextElementName: string;
|
|
4
|
+
queryAlias: string;
|
|
5
|
+
parameters: any[];
|
|
6
|
+
restrictions?: any;
|
|
7
|
+
}
|
|
8
|
+
export interface CommandDefinition {
|
|
9
|
+
contextElementName: string;
|
|
10
|
+
parameters: any;
|
|
11
|
+
}
|
|
12
|
+
export interface ModelStrategy {
|
|
13
|
+
query(queryDefinition: QueryDefinition, authContext: AuthContext, callback?: (result: any) => void): Promise<any>;
|
|
14
|
+
command(commandDefinition: CommandDefinition, authContext: AuthContext): Promise<any>;
|
|
15
|
+
setAuthToken?(token: string | null): void;
|
|
16
|
+
}
|
|
17
|
+
export interface QueryStrategy extends ModelStrategy {
|
|
18
|
+
execute(queryDefinition: QueryDefinition, authContext: AuthContext, callback?: (result: any) => void): Promise<any>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=query-strategy.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcote.tech/arc",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.12",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Przemysław Krasiński [arcote.tech]",
|
|
7
7
|
"description": "Arc is a framework designed to align code closely with business logic, streamlining development and enhancing productivity.",
|