@arcote.tech/arc 0.1.6 → 0.1.7
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.d.ts +1 -0
- package/dist/context/element.d.ts +0 -2
- package/dist/context/event.d.ts +2 -2
- package/dist/elements/id.d.ts +4 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +114 -16
- package/dist/view/index.d.ts +2 -0
- package/dist/view/queries/abstract-view-query.d.ts +1 -2
- package/dist/view/queries/find-one.d.ts +2 -1
- package/dist/view/queries/find.d.ts +2 -1
- package/dist/view/query-builders/find-one.d.ts +2 -1
- package/dist/view/query-builders/find.d.ts +2 -1
- package/dist/view/record.d.ts +4 -0
- package/dist/view/static-view.d.ts +43 -0
- package/dist/view/view.d.ts +1 -0
- package/package.json +1 -1
|
@@ -30,6 +30,7 @@ export declare class ArcCommand<Name extends string, Params extends ArcObjectAny
|
|
|
30
30
|
commandClient: (ctx: any) => (Params extends ArcObjectAny ? (params: $type<Params>) => Promise<$type<Results[number]>> : () => Promise<$type<Results[number]>>) & {
|
|
31
31
|
params: Params;
|
|
32
32
|
};
|
|
33
|
+
getUsedElements(): Elements;
|
|
33
34
|
protected clone(): ArcCommand<Name, Params, Results, Elements>;
|
|
34
35
|
toJsonSchema(): {
|
|
35
36
|
type: string;
|
package/dist/context/event.d.ts
CHANGED
|
@@ -30,7 +30,7 @@ export type ArcEventInstance<Event extends ArcEventAny> = {
|
|
|
30
30
|
payload: Event["payload"] extends ArcObjectAny ? $type<Event["payload"]> : undefined;
|
|
31
31
|
} & EventMetadata;
|
|
32
32
|
export type ArcEventAny = ArcEvent<any, any>;
|
|
33
|
-
export declare function event<const Name extends string, PayloadShape extends ArcRawShape | undefined>(name: Name, payload?: PayloadShape): ArcEvent<Name, PayloadShape extends ArcRawShape ? ArcObject<PayloadShape, [{
|
|
33
|
+
export declare function event<const Name extends string, PayloadShape extends ArcObjectAny | ArcRawShape | undefined>(name: Name, payload?: PayloadShape): ArcEvent<Name, PayloadShape extends ArcRawShape ? ArcObject<PayloadShape, [{
|
|
34
34
|
name: "type";
|
|
35
35
|
validator: (value: any) => false | {
|
|
36
36
|
current: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
|
|
@@ -39,5 +39,5 @@ export declare function event<const Name extends string, PayloadShape extends Ar
|
|
|
39
39
|
}, {
|
|
40
40
|
name: "schema";
|
|
41
41
|
validator: (value: any) => false | { [key in keyof PayloadShape]: ReturnType<PayloadShape[key]["validate"]>; };
|
|
42
|
-
}]> : undefined>;
|
|
42
|
+
}]> : PayloadShape extends ArcObjectAny ? PayloadShape : undefined>;
|
|
43
43
|
//# sourceMappingURL=event.d.ts.map
|
package/dist/elements/id.d.ts
CHANGED
|
@@ -7,10 +7,11 @@ export declare class ArcCustomId<Brand extends string | symbol, CreateFn extends
|
|
|
7
7
|
get(...args: Parameters<CreateFn>): util.GetType<this>;
|
|
8
8
|
}
|
|
9
9
|
export declare class ArcId<Brand extends string | symbol> extends ArcBranded<ArcString, Brand> {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
private generateFn?;
|
|
11
|
+
constructor(name: Brand, generateFn?: (() => string) | undefined);
|
|
12
|
+
generate(): ReturnType<this["deserialize"]>;
|
|
12
13
|
}
|
|
13
14
|
export type ArcIdAny = ArcId<any> | ArcCustomId<any, any>;
|
|
14
|
-
export declare function id<Brand extends string | symbol>(name: Brand): ArcId<Brand>;
|
|
15
|
+
export declare function id<Brand extends string | symbol>(name: Brand, generateFn?: () => string): ArcId<Brand>;
|
|
15
16
|
export declare function customId<Brand extends string | symbol, CreateFn extends (...args: any[]) => string>(name: Brand, createFn: CreateFn): ArcCustomId<Brand, CreateFn>;
|
|
16
17
|
//# sourceMappingURL=id.d.ts.map
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -321,18 +321,23 @@ class ArcCustomId extends ArcBranded {
|
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
class ArcId extends ArcBranded {
|
|
324
|
-
|
|
324
|
+
generateFn;
|
|
325
|
+
constructor(name, generateFn) {
|
|
325
326
|
super(string(), name);
|
|
327
|
+
this.generateFn = generateFn;
|
|
326
328
|
}
|
|
327
329
|
generate() {
|
|
330
|
+
if (this.generateFn) {
|
|
331
|
+
return this.generateFn();
|
|
332
|
+
}
|
|
328
333
|
var timestamp = (new Date().getTime() / 1000 | 0).toString(16);
|
|
329
334
|
return timestamp + "xxxxxxxxxxxxxxxx".replace(/[x]/g, function() {
|
|
330
335
|
return (Math.random() * 16 | 0).toString(16);
|
|
331
336
|
}).toLowerCase();
|
|
332
337
|
}
|
|
333
338
|
}
|
|
334
|
-
function id(name) {
|
|
335
|
-
return new ArcId(name);
|
|
339
|
+
function id(name, generateFn) {
|
|
340
|
+
return new ArcId(name, generateFn);
|
|
336
341
|
}
|
|
337
342
|
function customId(name, createFn) {
|
|
338
343
|
return new ArcCustomId(name, createFn);
|
|
@@ -1494,6 +1499,9 @@ class ArcCommand extends ArcContextElement {
|
|
|
1494
1499
|
return this._handler?.(ctx, params);
|
|
1495
1500
|
}, { params: this._params });
|
|
1496
1501
|
};
|
|
1502
|
+
getUsedElements() {
|
|
1503
|
+
return this._elements || [];
|
|
1504
|
+
}
|
|
1497
1505
|
clone() {
|
|
1498
1506
|
const clone = new ArcCommand(this.name);
|
|
1499
1507
|
clone._description = this._description;
|
|
@@ -1660,15 +1668,6 @@ class ArcEvent extends ArcContextElementWithStore {
|
|
|
1660
1668
|
delete: false
|
|
1661
1669
|
};
|
|
1662
1670
|
}
|
|
1663
|
-
const isSystemUser = authContext.roles.includes("system") || authContext.roles.includes("admin");
|
|
1664
|
-
if (!isSystemUser) {
|
|
1665
|
-
return {
|
|
1666
|
-
read: false,
|
|
1667
|
-
write: false,
|
|
1668
|
-
modify: false,
|
|
1669
|
-
delete: false
|
|
1670
|
-
};
|
|
1671
|
-
}
|
|
1672
1671
|
return {
|
|
1673
1672
|
read: true,
|
|
1674
1673
|
write: true,
|
|
@@ -1697,7 +1696,7 @@ class ArcEvent extends ArcContextElementWithStore {
|
|
|
1697
1696
|
};
|
|
1698
1697
|
}
|
|
1699
1698
|
function event(name, payload) {
|
|
1700
|
-
return new ArcEvent(name, payload ? new ArcObject(payload) : undefined);
|
|
1699
|
+
return new ArcEvent(name, payload ? payload instanceof ArcObject ? payload : new ArcObject(payload) : undefined);
|
|
1701
1700
|
}
|
|
1702
1701
|
// context/query-builder-context.ts
|
|
1703
1702
|
class QueryBuilderContext {
|
|
@@ -3122,8 +3121,23 @@ class ArcViewQuery extends ArcSerializableQuery {
|
|
|
3122
3121
|
this.nextResult(this.lastResult);
|
|
3123
3122
|
}
|
|
3124
3123
|
}
|
|
3125
|
-
|
|
3126
3124
|
// view/queries/find.ts
|
|
3125
|
+
class QueryViewResult {
|
|
3126
|
+
result;
|
|
3127
|
+
constructor(result) {
|
|
3128
|
+
this.result = result;
|
|
3129
|
+
}
|
|
3130
|
+
get(id3) {
|
|
3131
|
+
return id3 ? this.result.find((r) => r._id === id3) : undefined;
|
|
3132
|
+
}
|
|
3133
|
+
map(callbackfn) {
|
|
3134
|
+
return this.result.map(callbackfn);
|
|
3135
|
+
}
|
|
3136
|
+
toArray() {
|
|
3137
|
+
return this.result;
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3127
3141
|
class ArcViewFindQuery extends ArcViewQuery {
|
|
3128
3142
|
params;
|
|
3129
3143
|
constructor(view, params) {
|
|
@@ -3186,7 +3200,6 @@ class ArcViewFindQuery extends ArcViewQuery {
|
|
|
3186
3200
|
return result;
|
|
3187
3201
|
}
|
|
3188
3202
|
}
|
|
3189
|
-
|
|
3190
3203
|
// view/query-builders/find.ts
|
|
3191
3204
|
class ArcViewFindQueryBuilder {
|
|
3192
3205
|
view;
|
|
@@ -3207,7 +3220,86 @@ class ArcViewFindQueryBuilder {
|
|
|
3207
3220
|
return this.queryContext.runQuery(this.toQuery());
|
|
3208
3221
|
}
|
|
3209
3222
|
}
|
|
3210
|
-
|
|
3223
|
+
// view/static-view.ts
|
|
3224
|
+
class ArcStaticView extends ArcContextElement {
|
|
3225
|
+
name;
|
|
3226
|
+
id;
|
|
3227
|
+
schema;
|
|
3228
|
+
_description;
|
|
3229
|
+
_items = [];
|
|
3230
|
+
constructor(name, id3, schema) {
|
|
3231
|
+
super();
|
|
3232
|
+
this.name = name;
|
|
3233
|
+
this.id = id3;
|
|
3234
|
+
this.schema = schema;
|
|
3235
|
+
}
|
|
3236
|
+
description(description) {
|
|
3237
|
+
const clone = this.clone();
|
|
3238
|
+
clone._description = description;
|
|
3239
|
+
return clone;
|
|
3240
|
+
}
|
|
3241
|
+
addItems(items) {
|
|
3242
|
+
const clone = this.clone();
|
|
3243
|
+
clone._items = [...this._items, ...items];
|
|
3244
|
+
return clone;
|
|
3245
|
+
}
|
|
3246
|
+
queryBuilder = (context3, authContext) => {
|
|
3247
|
+
return {
|
|
3248
|
+
find: (options) => {
|
|
3249
|
+
return {
|
|
3250
|
+
toQuery: () => ({
|
|
3251
|
+
run: () => {
|
|
3252
|
+
return this._items;
|
|
3253
|
+
}
|
|
3254
|
+
})
|
|
3255
|
+
};
|
|
3256
|
+
},
|
|
3257
|
+
findOne: (where) => {
|
|
3258
|
+
return {
|
|
3259
|
+
toQuery: () => ({
|
|
3260
|
+
run: () => {
|
|
3261
|
+
if (!where)
|
|
3262
|
+
return this._items[0] || null;
|
|
3263
|
+
const item = this._items.find((item2) => {
|
|
3264
|
+
return Object.entries(where).every(([key, value]) => {
|
|
3265
|
+
return item2[key] === value;
|
|
3266
|
+
});
|
|
3267
|
+
});
|
|
3268
|
+
return item || null;
|
|
3269
|
+
}
|
|
3270
|
+
})
|
|
3271
|
+
};
|
|
3272
|
+
}
|
|
3273
|
+
};
|
|
3274
|
+
};
|
|
3275
|
+
commandContext = (dataStorage, publishEvent, authContext) => {
|
|
3276
|
+
const store = dataStorage.getStore(this.name);
|
|
3277
|
+
return {
|
|
3278
|
+
find: async (options) => {
|
|
3279
|
+
return this._items;
|
|
3280
|
+
},
|
|
3281
|
+
findOne: async (where) => {
|
|
3282
|
+
if (!where)
|
|
3283
|
+
return this._items[0] || null;
|
|
3284
|
+
const item = this._items.find((item2) => {
|
|
3285
|
+
return Object.entries(where).every(([key, value]) => {
|
|
3286
|
+
return item2[key] === value;
|
|
3287
|
+
});
|
|
3288
|
+
});
|
|
3289
|
+
return item || null;
|
|
3290
|
+
}
|
|
3291
|
+
};
|
|
3292
|
+
};
|
|
3293
|
+
clone() {
|
|
3294
|
+
const clone = new ArcStaticView(this.name, this.id, this.schema);
|
|
3295
|
+
clone._description = this._description;
|
|
3296
|
+
clone._items = [...this._items];
|
|
3297
|
+
return clone;
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
function staticView(name, id3, schema) {
|
|
3301
|
+
return new ArcStaticView(name, id3, schema);
|
|
3302
|
+
}
|
|
3211
3303
|
// view/queries/find-one.ts
|
|
3212
3304
|
class ArcViewFindOneQuery extends ArcViewQuery {
|
|
3213
3305
|
params;
|
|
@@ -3464,6 +3556,7 @@ export {
|
|
|
3464
3556
|
view,
|
|
3465
3557
|
stringEnum,
|
|
3466
3558
|
string,
|
|
3559
|
+
staticView,
|
|
3467
3560
|
rtcClientFactory,
|
|
3468
3561
|
route,
|
|
3469
3562
|
record,
|
|
@@ -3491,6 +3584,7 @@ export {
|
|
|
3491
3584
|
StoreState,
|
|
3492
3585
|
SQLiteAdapter,
|
|
3493
3586
|
RemoteModelClient,
|
|
3587
|
+
QueryViewResult,
|
|
3494
3588
|
QueryCache,
|
|
3495
3589
|
QueryBuilderContext,
|
|
3496
3590
|
ModelBase,
|
|
@@ -3500,9 +3594,13 @@ export {
|
|
|
3500
3594
|
ForkedStoreState,
|
|
3501
3595
|
ForkedDataStorage,
|
|
3502
3596
|
DataStorage,
|
|
3597
|
+
ArcViewQuery,
|
|
3598
|
+
ArcViewFindQueryBuilder,
|
|
3599
|
+
ArcViewFindQuery,
|
|
3503
3600
|
ArcView,
|
|
3504
3601
|
ArcStringEnum,
|
|
3505
3602
|
ArcString,
|
|
3603
|
+
ArcStaticView,
|
|
3506
3604
|
ArcRoute,
|
|
3507
3605
|
ArcRecord,
|
|
3508
3606
|
ArcQueryBuilder,
|
package/dist/view/index.d.ts
CHANGED
|
@@ -2,11 +2,10 @@ import { ArcSerializableQuery } from "../../context/serializable-query";
|
|
|
2
2
|
import type { DataStorage, ListenerEvent, StoreState } from "../../data-storage";
|
|
3
3
|
import type { ArcIdAny, ArcObjectAny } from "../../elements";
|
|
4
4
|
import type { $type } from "../../utils";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ArcViewAny } from "../view";
|
|
6
6
|
export type ArcViewItem<Id extends ArcIdAny, Schema extends ArcObjectAny> = {
|
|
7
7
|
_id: $type<Id>;
|
|
8
8
|
} & $type<Schema>;
|
|
9
|
-
export type ArcViewAny = ArcView<any, any, any, any>;
|
|
10
9
|
export declare abstract class ArcViewQuery<View extends ArcViewAny, Result, Params> extends ArcSerializableQuery<Result, Params> {
|
|
11
10
|
protected view: View;
|
|
12
11
|
protected bindedChangeHandler: (changes: ListenerEvent<ArcViewItem<View["id"], View["schema"]>>[]) => void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ListenerEvent, StoreState } from "../../data-storage";
|
|
2
2
|
import type { FindOptions } from "../../data-storage/types";
|
|
3
|
-
import {
|
|
3
|
+
import type { ArcViewAny } from "../view";
|
|
4
|
+
import { ArcViewQuery, type ArcViewItem } from "./abstract-view-query";
|
|
4
5
|
export declare class ArcViewFindOneQuery<View extends ArcViewAny> extends ArcViewQuery<View, ArcViewItem<View["id"], View["schema"]> | undefined, FindOptions<ArcViewItem<View["id"], View["schema"]>>> {
|
|
5
6
|
protected params: FindOptions<ArcViewItem<View["id"], View["schema"]>>;
|
|
6
7
|
constructor(view: View, params: FindOptions<ArcViewItem<View["id"], View["schema"]>>);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ListenerEvent, StoreState } from "../../data-storage";
|
|
2
2
|
import type { FindOptions } from "../../data-storage/types";
|
|
3
3
|
import type { util } from "../../utils";
|
|
4
|
-
import {
|
|
4
|
+
import type { ArcViewAny } from "../view";
|
|
5
|
+
import { ArcViewQuery, type ArcViewItem } from "./abstract-view-query";
|
|
5
6
|
export declare class QueryViewResult<V extends ArcViewAny> {
|
|
6
7
|
private result;
|
|
7
8
|
constructor(result: ArcViewItem<V["id"], V["schema"]>[]);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { QueryBuilderContext } from "../../context/query-builder-context";
|
|
2
2
|
import type { FindOptions } from "../../data-storage/types";
|
|
3
|
-
import type {
|
|
3
|
+
import type { ArcViewItem } from "../queries/abstract-view-query";
|
|
4
4
|
import { ArcViewFindOneQuery } from "../queries/find-one";
|
|
5
|
+
import type { ArcViewAny } from "../view";
|
|
5
6
|
export declare class ArcViewFindOneQueryBuilder<V extends ArcViewAny> {
|
|
6
7
|
private view;
|
|
7
8
|
protected queryContext: QueryBuilderContext;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { QueryBuilderContext } from "../../context/query-builder-context";
|
|
2
2
|
import type { FindOptions } from "../../data-storage/types";
|
|
3
|
-
import type {
|
|
3
|
+
import type { ArcViewItem } from "../queries/abstract-view-query";
|
|
4
4
|
import { ArcViewFindQuery } from "../queries/find";
|
|
5
|
+
import type { ArcViewAny } from "../view";
|
|
5
6
|
export declare class ArcViewFindQueryBuilder<V extends ArcViewAny> {
|
|
6
7
|
private view;
|
|
7
8
|
protected queryContext: QueryBuilderContext;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ArcStaticViewAny, ArcStaticViewRecord } from "./static-view";
|
|
2
|
+
import type { ArcViewAny, ArcViewRecord } from "./view";
|
|
3
|
+
export type ArcAnyViewRecord<View extends ArcViewAny | ArcStaticViewAny> = View extends ArcViewAny ? ArcViewRecord<View> : View extends ArcStaticViewAny ? ArcStaticViewRecord<View> : never;
|
|
4
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ArcQuery } from "../context";
|
|
2
|
+
import { ArcContextElement, type AuthContext, type PublishEventFunction } from "../context/element";
|
|
3
|
+
import type { QueryBuilderContext } from "../context/query-builder-context";
|
|
4
|
+
import type { DataStorage } from "../data-storage";
|
|
5
|
+
import type { FindOptions } from "../data-storage/types";
|
|
6
|
+
import { type ArcIdAny, type ArcObjectAny } from "../elements";
|
|
7
|
+
import type { $type, objectUtil } from "../utils";
|
|
8
|
+
type ArcViewItem<Id extends ArcIdAny, Schema extends ArcObjectAny> = {
|
|
9
|
+
_id: $type<Id>;
|
|
10
|
+
} & $type<Schema>;
|
|
11
|
+
type ArcStaticViewItem<Id extends ArcIdAny, Schema extends ArcObjectAny> = {
|
|
12
|
+
_id: $type<Id>;
|
|
13
|
+
} & $type<Schema>;
|
|
14
|
+
export declare class ArcStaticView<Name extends string, Id extends ArcIdAny, Schema extends ArcObjectAny, Items extends ArcStaticViewItem<Id, Schema>[]> extends ArcContextElement<null, Name> {
|
|
15
|
+
readonly name: Name;
|
|
16
|
+
readonly id: Id;
|
|
17
|
+
readonly schema: Schema;
|
|
18
|
+
private _description?;
|
|
19
|
+
private _items;
|
|
20
|
+
constructor(name: Name, id: Id, schema: Schema);
|
|
21
|
+
description(description: string): ArcStaticView<Name, Id, Schema, Items>;
|
|
22
|
+
addItems<const Items extends ArcStaticViewItem<Id, Schema>[]>(items: Items): ArcStaticView<Name, Id, Schema, Items>;
|
|
23
|
+
queryBuilder: (context: QueryBuilderContext, authContext: AuthContext) => {
|
|
24
|
+
readonly find: (options?: FindOptions<ArcViewItem<Id, Schema>>) => {
|
|
25
|
+
toQuery: () => ArcQuery<Items>;
|
|
26
|
+
};
|
|
27
|
+
readonly findOne: (where: FindOptions<ArcViewItem<Id, Schema>>["where"]) => {
|
|
28
|
+
toQuery: () => {
|
|
29
|
+
run: () => ArcStaticViewItem<Id, Schema> | null;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
commandContext: (dataStorage: DataStorage, publishEvent: PublishEventFunction, authContext: AuthContext) => {
|
|
34
|
+
readonly find: (options: FindOptions<ArcViewItem<Id, Schema>>) => Promise<Items>;
|
|
35
|
+
readonly findOne: (where: FindOptions<ArcViewItem<Id, Schema>>["where"]) => Promise<ArcStaticViewItem<Id, Schema> | null>;
|
|
36
|
+
};
|
|
37
|
+
private clone;
|
|
38
|
+
}
|
|
39
|
+
export declare function staticView<Name extends string, Id extends ArcIdAny, Schema extends ArcObjectAny>(name: Name, id: Id, schema: Schema): ArcStaticView<Name, Id, Schema, []>;
|
|
40
|
+
export type ArcStaticViewAny = ArcStaticView<any, any, any, any>;
|
|
41
|
+
export type ArcStaticViewRecord<View extends ArcStaticView<any, any, any, any>> = objectUtil.simplify<ArcViewItem<View["id"], View["schema"]>>;
|
|
42
|
+
export type { ArcStaticViewItem };
|
|
43
|
+
//# sourceMappingURL=static-view.d.ts.map
|
package/dist/view/view.d.ts
CHANGED
|
@@ -61,5 +61,6 @@ export declare class ArcView<Name extends string, Id extends ArcIdAny, Schema ex
|
|
|
61
61
|
}
|
|
62
62
|
export declare function view<Name extends string, Id extends ArcIdAny, Schema extends ArcObjectAny>(name: Name, id: Id, schema: Schema): ArcView<Name, Id, Schema, any[]>;
|
|
63
63
|
export type ArcViewRecord<View extends ArcView<any, any, any, any>> = objectUtil.simplify<ArcViewItem<View["id"], View["schema"]>>;
|
|
64
|
+
export type ArcViewAny = ArcView<any, any, any, any>;
|
|
64
65
|
export {};
|
|
65
66
|
//# sourceMappingURL=view.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.7",
|
|
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.",
|