@arcote.tech/arc 0.7.7 → 0.7.9
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/context-element/aggregate/aggregate-data.d.ts +5 -0
- package/dist/context-element/aggregate/aggregate-element.d.ts +1 -1
- package/dist/context-element/command/command.d.ts +3 -3
- package/dist/context-element/function/arc-function-data.d.ts +9 -3
- package/dist/context-element/function/arc-function.d.ts +25 -7
- package/dist/index.js +64 -29
- package/dist/model/context-accessor.d.ts +7 -1
- package/package.json +1 -1
|
@@ -37,6 +37,8 @@ export interface AggregateMutateMethodEntry {
|
|
|
37
37
|
readonly cronExpression?: string;
|
|
38
38
|
readonly queryElements?: ArcContextElement<any>[];
|
|
39
39
|
readonly mutationElements?: ArcContextElement<any>[];
|
|
40
|
+
readonly protections?: ViewProtection[];
|
|
41
|
+
readonly isPrivate?: boolean;
|
|
40
42
|
}
|
|
41
43
|
/**
|
|
42
44
|
* Cron method entry extracted at build time.
|
|
@@ -51,7 +53,10 @@ export interface AggregateCronMethodEntry {
|
|
|
51
53
|
*/
|
|
52
54
|
export interface AggregateQueryMethodEntry {
|
|
53
55
|
readonly name: string;
|
|
56
|
+
readonly params?: ArcObjectAny | null;
|
|
54
57
|
readonly handler: Function | false | null;
|
|
58
|
+
readonly protections?: ViewProtection[];
|
|
59
|
+
readonly isPrivate?: boolean;
|
|
55
60
|
}
|
|
56
61
|
/**
|
|
57
62
|
* Resolve mutateMethod return type from entry fields.
|
|
@@ -150,7 +150,7 @@ export declare class ArcAggregateElement<Name extends string = string, Id extend
|
|
|
150
150
|
params: ReturnFn["data"]["params"];
|
|
151
151
|
handler: ReturnFn["data"]["handler"];
|
|
152
152
|
handlerReturn: ReturnFn["data"]["handler"] extends (...args: any[]) => Promise<infer HR> ? HR : void;
|
|
153
|
-
result: ReturnFn["data"]["
|
|
153
|
+
result: ReturnFn["data"]["results"] extends [] ? never : $type<ReturnFn["data"]["results"][number]>;
|
|
154
154
|
}
|
|
155
155
|
], QueryMethods>;
|
|
156
156
|
cron(expression: string): ArcAggregateElement<Name, Id, Schema, Events, MutateMethods, QueryMethods>;
|
|
@@ -47,10 +47,10 @@ export declare class ArcCommand<const Data extends ArcCommandData> extends ArcCo
|
|
|
47
47
|
withParams<NewParams extends ArcRawShape>(schema: NewParams | ArcObject<NewParams>): ArcCommand<Merge<Data, {
|
|
48
48
|
params: ArcObject<NewParams>;
|
|
49
49
|
}>>;
|
|
50
|
-
withResult<NewResults extends ArcRawShape[]>(...schemas: NewResults): ArcCommand<Merge<Data, {
|
|
51
|
-
results: { [K in keyof NewResults]: ArcObject<NewResults[K]
|
|
50
|
+
withResult<NewResults extends (ArcRawShape | ArcObjectAny)[]>(...schemas: NewResults): ArcCommand<Merge<Data, {
|
|
51
|
+
results: { [K in keyof NewResults]: NewResults[K] extends ArcObjectAny ? NewResults[K] : NewResults[K] extends ArcRawShape ? ArcObject<NewResults[K]> : never; };
|
|
52
52
|
}>>;
|
|
53
|
-
handle<Handler extends ArcCommandHandler<ArcCommandContextFromData<Data>, Data["params"] extends ArcObjectAny ? $type<Data["params"]> : null, $type<Data["results"][number]>> | false>(handler: Handler): ArcCommand<Merge<Data, {
|
|
53
|
+
handle<Handler extends ArcCommandHandler<ArcCommandContextFromData<Data>, Data["params"] extends ArcObjectAny ? $type<Data["params"]> : null, Data["results"] extends [] ? void : $type<Data["results"][number]>> | false>(handler: Handler): ArcCommand<Merge<Data, {
|
|
54
54
|
handler: Handler;
|
|
55
55
|
}>>;
|
|
56
56
|
protectBy<T extends ArcTokenAny>(token: T, check: FnProtectionCheck<T>): ArcCommand<Merge<Data, {
|
|
@@ -23,7 +23,7 @@ export type TypedTokenInstance<T extends ArcTokenAny> = T extends ArcToken<any,
|
|
|
23
23
|
* - `Record` → access allowed + merged into WHERE clause (query context)
|
|
24
24
|
* + validated on writes (scope enforcement)
|
|
25
25
|
*/
|
|
26
|
-
export type FnProtectionCheck<T extends ArcTokenAny> = (
|
|
26
|
+
export type FnProtectionCheck<T extends ArcTokenAny> = (params: T extends import("../../token/token").ArcToken<any, infer P extends import("../../elements/object").ArcRawShape, any, any> ? import("../../utils/types/get-type").$type<import("../../elements/object").ArcObject<P>> : Record<string, any>) => boolean | Record<string, unknown> | Promise<boolean | Record<string, unknown>>;
|
|
27
27
|
/**
|
|
28
28
|
* Protection configuration for an ArcFunction.
|
|
29
29
|
*/
|
|
@@ -55,12 +55,18 @@ type ProtectionTokens<Protections extends FnProtection[]> = Protections[number][
|
|
|
55
55
|
*/
|
|
56
56
|
export type ArcFunctionData = {
|
|
57
57
|
params: ArcObjectAny | null;
|
|
58
|
-
|
|
58
|
+
results: ArcObjectAny[];
|
|
59
59
|
queryElements: ArcContextElement<any>[];
|
|
60
60
|
mutationElements: ArcContextElement<any>[];
|
|
61
61
|
protections: FnProtection[];
|
|
62
62
|
handler: Function | false | null;
|
|
63
63
|
description?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Private (server-internal) marker. When true, the wrapping aggregate
|
|
66
|
+
* MUST NOT expose this function over commandWire — only server-side
|
|
67
|
+
* callers (listeners, routes, commands) can invoke it via ctx.mutate.
|
|
68
|
+
*/
|
|
69
|
+
isPrivate?: boolean;
|
|
64
70
|
};
|
|
65
71
|
/**
|
|
66
72
|
* Unified function context — single source of truth for all handle() signatures.
|
|
@@ -76,6 +82,6 @@ export type FnContext<Data extends ArcFunctionData, ExtraCtx = {}> = ElementCont
|
|
|
76
82
|
/**
|
|
77
83
|
* Handler function type for ArcFunction.
|
|
78
84
|
*/
|
|
79
|
-
export type FnHandler<Data extends ArcFunctionData, ExtraCtx = {}> = (ctx: FnContext<Data, ExtraCtx>, params: Data["params"] extends ArcObjectAny ? $type<Data["params"]> : void) => Promise<Data["
|
|
85
|
+
export type FnHandler<Data extends ArcFunctionData, ExtraCtx = {}> = (ctx: FnContext<Data, ExtraCtx>, params: Data["params"] extends ArcObjectAny ? $type<Data["params"]> : void) => Promise<Data["results"] extends [] ? void : $type<Data["results"][number]>>;
|
|
80
86
|
export {};
|
|
81
87
|
//# sourceMappingURL=arc-function-data.d.ts.map
|
|
@@ -36,8 +36,17 @@ export declare class ArcFunction<const Data extends ArcFunctionData, ExtraCtx =
|
|
|
36
36
|
withParams<const S extends ArcRawShape>(schema: S | ArcObject<S>): ArcFunction<Merge<Data, {
|
|
37
37
|
params: ArcObject<S>;
|
|
38
38
|
}>, ExtraCtx>;
|
|
39
|
-
withResult<const
|
|
40
|
-
|
|
39
|
+
withResult<const Schemas extends (ArcRawShape | ArcObjectAny)[]>(...schemas: Schemas): ArcFunction<Merge<Data, {
|
|
40
|
+
results: { [K in keyof Schemas]: Schemas[K] extends ArcObjectAny ? Schemas[K] : Schemas[K] extends ArcRawShape ? ArcObject<Schemas[K], [{
|
|
41
|
+
name: "type";
|
|
42
|
+
validator: (value: any) => false | {
|
|
43
|
+
current: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
|
|
44
|
+
expected: "object";
|
|
45
|
+
};
|
|
46
|
+
}, {
|
|
47
|
+
name: "schema";
|
|
48
|
+
validator: (value: any) => false | (Schemas[K] extends infer T extends ArcRawShape ? { [key in keyof T]: ReturnType<T[key]["validate"]>; } : never);
|
|
49
|
+
}]> : never; };
|
|
41
50
|
}>, ExtraCtx>;
|
|
42
51
|
query<const Elements extends ArcContextElement<any>[]>(elements: Elements): ArcFunction<Merge<Data, {
|
|
43
52
|
queryElements: Elements;
|
|
@@ -54,6 +63,15 @@ export declare class ArcFunction<const Data extends ArcFunctionData, ExtraCtx =
|
|
|
54
63
|
description<const Desc extends string>(desc: Desc): ArcFunction<Merge<Data, {
|
|
55
64
|
description: Desc;
|
|
56
65
|
}>, ExtraCtx>;
|
|
66
|
+
/**
|
|
67
|
+
* Mark this function as private (server-internal). The wrapping aggregate
|
|
68
|
+
* MUST NOT expose private mutateMethod/clientQuery via commandWire — only
|
|
69
|
+
* server-side callers (listeners, routes, commands) can invoke it through
|
|
70
|
+
* `ctx.mutate.*` / `ctx.query.*`. Browser-side invocation throws.
|
|
71
|
+
*/
|
|
72
|
+
private(): ArcFunction<Merge<Data, {
|
|
73
|
+
isPrivate: true;
|
|
74
|
+
}>, ExtraCtx>;
|
|
57
75
|
handle<Handler extends ((ctx: FnContext<Data, ExtraCtx>, ...args: Data["params"] extends ArcObjectAny ? [$type<Data["params"]>] : []) => Promise<any>) | false>(handler: Handler): ArcFunction<Merge<Data, {
|
|
58
76
|
handler: Handler;
|
|
59
77
|
}>, ExtraCtx>;
|
|
@@ -62,7 +80,7 @@ export declare class ArcFunction<const Data extends ArcFunctionData, ExtraCtx =
|
|
|
62
80
|
get protections(): FnProtection[];
|
|
63
81
|
get handler(): false | Function | null;
|
|
64
82
|
get params(): ArcObjectAny | null;
|
|
65
|
-
get
|
|
83
|
+
get results(): ArcObjectAny[];
|
|
66
84
|
/**
|
|
67
85
|
* Verify all protections pass for given token instances.
|
|
68
86
|
* All protections must pass (logical AND).
|
|
@@ -78,12 +96,12 @@ export declare class ArcFunction<const Data extends ArcFunctionData, ExtraCtx =
|
|
|
78
96
|
*/
|
|
79
97
|
toJsonSchema(): {
|
|
80
98
|
params: any;
|
|
81
|
-
|
|
99
|
+
results: any[];
|
|
82
100
|
};
|
|
83
101
|
}
|
|
84
102
|
export declare const defaultFunctionData: {
|
|
85
103
|
readonly params: null;
|
|
86
|
-
readonly
|
|
104
|
+
readonly results: [];
|
|
87
105
|
readonly queryElements: [];
|
|
88
106
|
readonly mutationElements: [];
|
|
89
107
|
readonly protections: [];
|
|
@@ -96,7 +114,7 @@ export type DefaultFunctionData = typeof defaultFunctionData;
|
|
|
96
114
|
*/
|
|
97
115
|
export declare function arcFunction(): ArcFunction<{
|
|
98
116
|
readonly params: null;
|
|
99
|
-
readonly
|
|
117
|
+
readonly results: [];
|
|
100
118
|
readonly queryElements: [];
|
|
101
119
|
readonly mutationElements: [];
|
|
102
120
|
readonly protections: [];
|
|
@@ -109,7 +127,7 @@ export declare function arcFunction(): ArcFunction<{
|
|
|
109
127
|
*/
|
|
110
128
|
export declare function arcFunctionWithCtx<ExtraCtx>(): ArcFunction<{
|
|
111
129
|
readonly params: null;
|
|
112
|
-
readonly
|
|
130
|
+
readonly results: [];
|
|
113
131
|
readonly queryElements: [];
|
|
114
132
|
readonly mutationElements: [];
|
|
115
133
|
readonly protections: [];
|
package/dist/index.js
CHANGED
|
@@ -1884,10 +1884,11 @@ class ArcFunction {
|
|
|
1884
1884
|
params: schema instanceof ArcObject ? schema : new ArcObject(schema)
|
|
1885
1885
|
});
|
|
1886
1886
|
}
|
|
1887
|
-
withResult(
|
|
1887
|
+
withResult(...schemas) {
|
|
1888
|
+
const results = schemas.map((s) => s instanceof ArcObject ? s : new ArcObject(s));
|
|
1888
1889
|
return new ArcFunction({
|
|
1889
1890
|
...this.data,
|
|
1890
|
-
|
|
1891
|
+
results
|
|
1891
1892
|
});
|
|
1892
1893
|
}
|
|
1893
1894
|
query(elements) {
|
|
@@ -1915,6 +1916,12 @@ class ArcFunction {
|
|
|
1915
1916
|
description: desc
|
|
1916
1917
|
});
|
|
1917
1918
|
}
|
|
1919
|
+
private() {
|
|
1920
|
+
return new ArcFunction({
|
|
1921
|
+
...this.data,
|
|
1922
|
+
isPrivate: true
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1918
1925
|
handle(handler) {
|
|
1919
1926
|
return new ArcFunction({
|
|
1920
1927
|
...this.data,
|
|
@@ -1936,8 +1943,8 @@ class ArcFunction {
|
|
|
1936
1943
|
get params() {
|
|
1937
1944
|
return this.data.params;
|
|
1938
1945
|
}
|
|
1939
|
-
get
|
|
1940
|
-
return this.data.
|
|
1946
|
+
get results() {
|
|
1947
|
+
return this.data.results;
|
|
1941
1948
|
}
|
|
1942
1949
|
async verifyProtections(tokens) {
|
|
1943
1950
|
if (!this.data.protections || this.data.protections.length === 0) {
|
|
@@ -1961,13 +1968,13 @@ class ArcFunction {
|
|
|
1961
1968
|
toJsonSchema() {
|
|
1962
1969
|
return {
|
|
1963
1970
|
params: this.data.params?.toJsonSchema?.() ?? null,
|
|
1964
|
-
|
|
1971
|
+
results: this.data.results.map((r) => r.toJsonSchema())
|
|
1965
1972
|
};
|
|
1966
1973
|
}
|
|
1967
1974
|
}
|
|
1968
1975
|
var defaultFunctionData = {
|
|
1969
1976
|
params: null,
|
|
1970
|
-
|
|
1977
|
+
results: [],
|
|
1971
1978
|
queryElements: [],
|
|
1972
1979
|
mutationElements: [],
|
|
1973
1980
|
protections: [],
|
|
@@ -2092,7 +2099,9 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2092
2099
|
params: configuredFn.data.params,
|
|
2093
2100
|
handler: configuredFn.data.handler,
|
|
2094
2101
|
queryElements: configuredFn.data.queryElements?.length ? configuredFn.data.queryElements : undefined,
|
|
2095
|
-
mutationElements: configuredFn.data.mutationElements?.length ? configuredFn.data.mutationElements : undefined
|
|
2102
|
+
mutationElements: configuredFn.data.mutationElements?.length ? configuredFn.data.mutationElements : undefined,
|
|
2103
|
+
protections: (configuredFn.data.protections ?? []).map((p) => ({ token: p.token, protectionFn: p.check })),
|
|
2104
|
+
isPrivate: configuredFn.data.isPrivate ?? false
|
|
2096
2105
|
};
|
|
2097
2106
|
return new ArcAggregateElement(this.name, this._id_factory, this.schema, this._events, this._protections, [...this._mutateMethods, entry], this._queryMethods, this._seeds);
|
|
2098
2107
|
}
|
|
@@ -2112,7 +2121,10 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2112
2121
|
const configuredFn = configure(baseFn);
|
|
2113
2122
|
const entry = {
|
|
2114
2123
|
name: methodName,
|
|
2115
|
-
|
|
2124
|
+
params: configuredFn.data.params,
|
|
2125
|
+
handler: configuredFn.data.handler,
|
|
2126
|
+
protections: (configuredFn.data.protections ?? []).map((p) => ({ token: p.token, protectionFn: p.check })),
|
|
2127
|
+
isPrivate: configuredFn.data.isPrivate ?? false
|
|
2116
2128
|
};
|
|
2117
2129
|
return new ArcAggregateElement(this.name, this._id_factory, this.schema, this._events, this._protections, this._mutateMethods, [...this._queryMethods, entry], this._seeds);
|
|
2118
2130
|
}
|
|
@@ -2198,7 +2210,6 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2198
2210
|
return result;
|
|
2199
2211
|
}
|
|
2200
2212
|
queryContext(adapters) {
|
|
2201
|
-
const privateQuery = this.buildPrivateQuery(adapters);
|
|
2202
2213
|
const auth = this.getAuth(adapters);
|
|
2203
2214
|
const AggCtor = this.Aggregate;
|
|
2204
2215
|
const result = {};
|
|
@@ -2206,7 +2217,8 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2206
2217
|
if (!method.handler)
|
|
2207
2218
|
continue;
|
|
2208
2219
|
const handler = method.handler;
|
|
2209
|
-
|
|
2220
|
+
const privateQuery = this.buildPrivateQuery(adapters, method.protections ?? []);
|
|
2221
|
+
const fn = (...args) => {
|
|
2210
2222
|
const ctx = {
|
|
2211
2223
|
$query: privateQuery,
|
|
2212
2224
|
$auth: auth,
|
|
@@ -2214,13 +2226,16 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2214
2226
|
};
|
|
2215
2227
|
return handler(ctx, ...args);
|
|
2216
2228
|
};
|
|
2229
|
+
fn.__isPrivate = method.isPrivate ?? false;
|
|
2230
|
+
result[method.name] = fn;
|
|
2217
2231
|
}
|
|
2218
2232
|
return result;
|
|
2219
2233
|
}
|
|
2220
|
-
buildPrivateQuery(adapters) {
|
|
2234
|
+
buildPrivateQuery(adapters, methodProtections = []) {
|
|
2221
2235
|
const viewName = this.name;
|
|
2222
|
-
const
|
|
2223
|
-
const
|
|
2236
|
+
const effectiveProtections = methodProtections.length > 0 ? methodProtections : this._protections;
|
|
2237
|
+
const restrictions = this.getScopeRestrictions(adapters, effectiveProtections);
|
|
2238
|
+
const isDenied = this.isScopeDenied(adapters, effectiveProtections);
|
|
2224
2239
|
const findRows = async (options) => {
|
|
2225
2240
|
if (adapters.dataStorage) {
|
|
2226
2241
|
if (restrictions) {
|
|
@@ -2258,8 +2273,7 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2258
2273
|
}
|
|
2259
2274
|
};
|
|
2260
2275
|
}
|
|
2261
|
-
isScopeDenied(adapters) {
|
|
2262
|
-
const protections = this._protections;
|
|
2276
|
+
isScopeDenied(adapters, protections = this._protections) {
|
|
2263
2277
|
if (protections.length === 0)
|
|
2264
2278
|
return false;
|
|
2265
2279
|
if (!adapters.authAdapter)
|
|
@@ -2282,8 +2296,7 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2282
2296
|
}
|
|
2283
2297
|
return { params: {}, tokenName: "" };
|
|
2284
2298
|
}
|
|
2285
|
-
getScopeRestrictions(adapters) {
|
|
2286
|
-
const protections = this._protections;
|
|
2299
|
+
getScopeRestrictions(adapters, protections = this._protections) {
|
|
2287
2300
|
if (protections.length === 0)
|
|
2288
2301
|
return null;
|
|
2289
2302
|
if (!adapters.authAdapter)
|
|
@@ -2299,16 +2312,16 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2299
2312
|
return result ?? null;
|
|
2300
2313
|
}
|
|
2301
2314
|
}
|
|
2302
|
-
console.log(`[Scope:${this.name}] no matching protection`);
|
|
2303
2315
|
return null;
|
|
2304
2316
|
}
|
|
2305
2317
|
mutateContext(adapters) {
|
|
2306
2318
|
const events = this._events;
|
|
2307
|
-
const privateQuery = this.buildPrivateQuery(adapters);
|
|
2308
2319
|
const auth = this.getAuth(adapters);
|
|
2309
2320
|
const aggregateName = this.name;
|
|
2310
|
-
const scopeRestrictions = this.getScopeRestrictions(adapters);
|
|
2311
2321
|
const buildMutateMethodCtx = (method) => {
|
|
2322
|
+
const methodProtections = method.protections ?? [];
|
|
2323
|
+
const privateQuery = this.buildPrivateQuery(adapters, methodProtections);
|
|
2324
|
+
const scopeRestrictions = this.getScopeRestrictions(adapters, methodProtections.length > 0 ? methodProtections : this._protections);
|
|
2312
2325
|
const ctx = {};
|
|
2313
2326
|
for (const entry of events) {
|
|
2314
2327
|
const arcEvent = entry.event;
|
|
@@ -2350,8 +2363,11 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2350
2363
|
};
|
|
2351
2364
|
const result = {};
|
|
2352
2365
|
for (const method of this._mutateMethods) {
|
|
2353
|
-
|
|
2366
|
+
const fn = async (params) => {
|
|
2354
2367
|
if (!method.handler) {
|
|
2368
|
+
if (method.isPrivate) {
|
|
2369
|
+
throw new Error(`Method "${aggregateName}.${method.name}" is private (server-only) and cannot be invoked from a client.`);
|
|
2370
|
+
}
|
|
2355
2371
|
if (!adapters.commandWire) {
|
|
2356
2372
|
throw new Error(`Method "${method.name}" is server-only but no commandWire (WebSocket) is available.`);
|
|
2357
2373
|
}
|
|
@@ -2364,6 +2380,8 @@ class ArcAggregateElement extends ArcContextElement {
|
|
|
2364
2380
|
const ctx = buildMutateMethodCtx(method);
|
|
2365
2381
|
return method.handler(ctx, params);
|
|
2366
2382
|
};
|
|
2383
|
+
fn.__isPrivate = method.isPrivate ?? false;
|
|
2384
|
+
result[method.name] = fn;
|
|
2367
2385
|
}
|
|
2368
2386
|
return result;
|
|
2369
2387
|
}
|
|
@@ -2399,7 +2417,7 @@ class ArcCommand extends ArcContextElement {
|
|
|
2399
2417
|
this.data = data;
|
|
2400
2418
|
this.#fn = fn ?? new ArcFunction({
|
|
2401
2419
|
params: data.params,
|
|
2402
|
-
|
|
2420
|
+
results: data.results,
|
|
2403
2421
|
queryElements: data.queryElements,
|
|
2404
2422
|
mutationElements: data.mutationElements,
|
|
2405
2423
|
protections: data.protections || [],
|
|
@@ -2430,7 +2448,8 @@ class ArcCommand extends ArcContextElement {
|
|
|
2430
2448
|
}, newFn);
|
|
2431
2449
|
}
|
|
2432
2450
|
withResult(...schemas) {
|
|
2433
|
-
|
|
2451
|
+
const newFn = this.#fn.withResult(...schemas);
|
|
2452
|
+
return new ArcCommand({ ...this.data, results: newFn.data.results }, newFn);
|
|
2434
2453
|
}
|
|
2435
2454
|
handle(handler) {
|
|
2436
2455
|
const newFn = new ArcFunction({
|
|
@@ -2532,7 +2551,7 @@ class ArcListener extends ArcContextElement {
|
|
|
2532
2551
|
this.data = data;
|
|
2533
2552
|
this.#fn = fn ?? new ArcFunction({
|
|
2534
2553
|
params: null,
|
|
2535
|
-
|
|
2554
|
+
results: [],
|
|
2536
2555
|
queryElements: data.queryElements,
|
|
2537
2556
|
mutationElements: data.mutationElements,
|
|
2538
2557
|
protections: [],
|
|
@@ -2648,7 +2667,7 @@ class ArcRoute extends ArcContextElement {
|
|
|
2648
2667
|
this.data = data;
|
|
2649
2668
|
this.#fn = fn ?? new ArcFunction({
|
|
2650
2669
|
params: null,
|
|
2651
|
-
|
|
2670
|
+
results: [],
|
|
2652
2671
|
queryElements: data.queryElements,
|
|
2653
2672
|
mutationElements: data.mutationElements,
|
|
2654
2673
|
protections: data.protections || [],
|
|
@@ -4375,19 +4394,26 @@ function buildContextAccessor(context2, adapters, contextMethod, onCall) {
|
|
|
4375
4394
|
if (typeof ctxFn !== "function")
|
|
4376
4395
|
continue;
|
|
4377
4396
|
const methods = ctxFn.call(element2, adapters);
|
|
4378
|
-
if (!methods
|
|
4397
|
+
if (!methods)
|
|
4398
|
+
continue;
|
|
4399
|
+
const elementName = element2.name;
|
|
4400
|
+
if (typeof methods === "function") {
|
|
4401
|
+
result[elementName] = (...args) => onCall({ element: elementName, method: "", args }, () => methods(...args));
|
|
4402
|
+
continue;
|
|
4403
|
+
}
|
|
4404
|
+
if (typeof methods !== "object")
|
|
4379
4405
|
continue;
|
|
4380
4406
|
const wrapped = {};
|
|
4381
4407
|
for (const [methodName, method] of Object.entries(methods)) {
|
|
4382
4408
|
if (typeof method !== "function")
|
|
4383
4409
|
continue;
|
|
4384
|
-
wrapped[methodName] = (...args) => onCall({ element:
|
|
4410
|
+
wrapped[methodName] = (...args) => onCall({ element: elementName, method: methodName, args }, () => method(...args));
|
|
4385
4411
|
}
|
|
4386
|
-
result[
|
|
4412
|
+
result[elementName] = wrapped;
|
|
4387
4413
|
}
|
|
4388
4414
|
return result;
|
|
4389
4415
|
}
|
|
4390
|
-
function executeDescriptor(descriptor, context2, adapters, contextMethod) {
|
|
4416
|
+
function executeDescriptor(descriptor, context2, adapters, contextMethod, options) {
|
|
4391
4417
|
const element2 = context2.get(descriptor.element);
|
|
4392
4418
|
if (!element2) {
|
|
4393
4419
|
throw new Error(`Element '${descriptor.element}' not found in context`);
|
|
@@ -4397,10 +4423,19 @@ function executeDescriptor(descriptor, context2, adapters, contextMethod) {
|
|
|
4397
4423
|
throw new Error(`Element '${descriptor.element}' has no ${contextMethod}`);
|
|
4398
4424
|
}
|
|
4399
4425
|
const methods = ctxFn.call(element2, adapters);
|
|
4426
|
+
if (typeof methods === "function") {
|
|
4427
|
+
if (options?.fromWire && methods.__isPrivate) {
|
|
4428
|
+
throw new Error(`Element "${descriptor.element}" is private and not callable from a client.`);
|
|
4429
|
+
}
|
|
4430
|
+
return methods(...descriptor.args);
|
|
4431
|
+
}
|
|
4400
4432
|
const method = methods?.[descriptor.method];
|
|
4401
4433
|
if (typeof method !== "function") {
|
|
4402
4434
|
throw new Error(`Method '${descriptor.method}' not found on '${descriptor.element}'`);
|
|
4403
4435
|
}
|
|
4436
|
+
if (options?.fromWire && method.__isPrivate) {
|
|
4437
|
+
throw new Error(`Method "${descriptor.element}.${descriptor.method}" is private and not callable from a client.`);
|
|
4438
|
+
}
|
|
4404
4439
|
return method(...descriptor.args);
|
|
4405
4440
|
}
|
|
4406
4441
|
|
|
@@ -46,6 +46,12 @@ export declare function buildContextAccessor<C extends ArcContextAny, R>(context
|
|
|
46
46
|
* @param context - ArcContext containing elements
|
|
47
47
|
* @param adapters - ModelAdapters for queryContext/mutateContext
|
|
48
48
|
* @param contextMethod - "queryContext" or "mutateContext"
|
|
49
|
+
* @param options - `fromWire: true` rejects calls to methods tagged
|
|
50
|
+
* `__isPrivate` (private mutateMethod/clientQuery). Server-side
|
|
51
|
+
* wire dispatchers MUST pass `fromWire: true`. Internal callers
|
|
52
|
+
* (replay, tests) may omit it.
|
|
49
53
|
*/
|
|
50
|
-
export declare function executeDescriptor(descriptor: ContextDescriptor, context: ArcContextAny, adapters: ModelAdapters, contextMethod: "queryContext" | "mutateContext"
|
|
54
|
+
export declare function executeDescriptor(descriptor: ContextDescriptor, context: ArcContextAny, adapters: ModelAdapters, contextMethod: "queryContext" | "mutateContext", options?: {
|
|
55
|
+
fromWire?: boolean;
|
|
56
|
+
}): any;
|
|
51
57
|
//# sourceMappingURL=context-accessor.d.ts.map
|
package/package.json
CHANGED