@arcote.tech/arc 0.3.1 → 0.3.3

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.
@@ -75,6 +75,15 @@ export interface EventPublisher {
75
75
  * @param views - Array of views to register
76
76
  */
77
77
  registerViews(views: ArcViewAny[]): void;
78
+ /**
79
+ * Subscribe to events of a specific type
80
+ * Used by listeners to react to events
81
+ *
82
+ * @param eventType - Event type name to subscribe to
83
+ * @param callback - Function to call when event is published
84
+ * @returns Unsubscribe function
85
+ */
86
+ subscribe(eventType: string, callback: (event: ArcEventInstance<ArcEventAny>) => Promise<void> | void): () => void;
78
87
  }
79
88
  /**
80
89
  * Local EventPublisher implementation
@@ -84,6 +93,7 @@ export declare class LocalEventPublisher implements EventPublisher {
84
93
  private readonly dataStorage;
85
94
  private views;
86
95
  private syncCallback?;
96
+ private subscribers;
87
97
  constructor(dataStorage: DataStorage);
88
98
  /**
89
99
  * Set a callback to be called after each event is published
@@ -94,7 +104,15 @@ export declare class LocalEventPublisher implements EventPublisher {
94
104
  * Register views that should be updated when events are published
95
105
  */
96
106
  registerViews(views: ArcViewAny[]): void;
107
+ /**
108
+ * Subscribe to events of a specific type
109
+ */
110
+ subscribe(eventType: string, callback: (event: ArcEventInstance<ArcEventAny>) => Promise<void> | void): () => void;
97
111
  publish(event: ArcEventInstance<ArcEventAny>): Promise<void>;
112
+ /**
113
+ * Notify all subscribers for an event type
114
+ */
115
+ private notifySubscribers;
98
116
  markSynced(eventIds: string[]): Promise<void>;
99
117
  getUnsyncedEvents(eventType?: string): Promise<EventWithSyncStatus[]>;
100
118
  /**
@@ -5,6 +5,7 @@
5
5
  * - Wire: Client-server communication
6
6
  * - CommandWire: Command execution over network
7
7
  * - EventPublisher: Event persistence and synchronization
8
+ * - QueryWire: Remote view queries via HTTP/SSE
8
9
  * - DataStorage: Data persistence (defined elsewhere)
9
10
  */
10
11
  export { AuthAdapter } from "./auth-adapter";
@@ -12,6 +13,8 @@ export type { DecodedToken } from "./auth-adapter";
12
13
  export { CommandWire } from "./command-wire";
13
14
  export { EventWire } from "./event-wire";
14
15
  export type { ReceivedEvent, SyncableEvent } from "./event-wire";
16
+ export { QueryWire } from "./query-wire";
17
+ export type { StreamConnection } from "./query-wire";
15
18
  export { Wire } from "./wire";
16
19
  export { EVENT_TABLES, LocalEventPublisher } from "./event-publisher";
17
20
  export type { EventPublisher, EventWithSyncStatus, StoredEvent, StoredEventSyncStatus, StoredEventTag, } from "./event-publisher";
@@ -0,0 +1,34 @@
1
+ /**
2
+ * QueryWire - Wire adapter for remote view queries via HTTP/SSE
3
+ *
4
+ * Provides:
5
+ * - One-shot queries via HTTP POST
6
+ * - Live queries via Server-Sent Events (SSE)
7
+ */
8
+ import { Wire } from "./wire";
9
+ export interface StreamConnection {
10
+ eventSource: EventSource;
11
+ unsubscribe: () => void;
12
+ }
13
+ export declare class QueryWire extends Wire {
14
+ constructor(baseUrl: string);
15
+ /**
16
+ * Execute a one-shot query on a view
17
+ *
18
+ * @param viewName - Name of the view to query
19
+ * @param options - Query options (where, orderBy, limit)
20
+ * @returns Query results
21
+ */
22
+ query(viewName: string, options?: any): Promise<any[]>;
23
+ /**
24
+ * Create a live query stream using SSE
25
+ *
26
+ * @param viewName - Name of the view to stream
27
+ * @param options - Query options (where, orderBy, limit)
28
+ * @param callback - Called when data changes
29
+ * @param token - Auth token for the stream (optional, uses wire token if not provided)
30
+ * @returns StreamConnection with unsubscribe method
31
+ */
32
+ stream(viewName: string, options: any, callback: (data: any[]) => void, token?: string | null): StreamConnection;
33
+ }
34
+ //# sourceMappingURL=query-wire.d.ts.map
@@ -5,13 +5,21 @@
5
5
  * for making authenticated requests to the server.
6
6
  */
7
7
  export declare class Wire {
8
- private readonly baseUrl;
9
8
  private token;
9
+ protected readonly baseUrl: string;
10
10
  constructor(baseUrl: string);
11
11
  /**
12
12
  * Set authentication token for requests
13
13
  */
14
14
  setAuthToken(token: string | null): void;
15
+ /**
16
+ * Get the current auth token
17
+ */
18
+ getAuthToken(): string | null;
19
+ /**
20
+ * Get the base URL
21
+ */
22
+ getBaseUrl(): string;
15
23
  /**
16
24
  * Make authenticated fetch request to server
17
25
  */
@@ -15,7 +15,7 @@ export declare class ArcContext<const Elements extends ArcContextElement<any>[]>
15
15
  * @param name - The name of the element to retrieve
16
16
  * @returns The element if found, undefined otherwise
17
17
  */
18
- get(name: string): Elements[number] | undefined;
18
+ get<E extends Elements[number]>(name: E["name"]): E | undefined;
19
19
  }
20
20
  /**
21
21
  * Create a new context from an array of elements
@@ -33,6 +33,99 @@ export declare class ArcContext<const Elements extends ArcContextElement<any>[]>
33
33
  * ```
34
34
  */
35
35
  export declare function context<const Elements extends ArcContextElement<any>[]>(elements: Elements): ArcContext<Elements>;
36
+ /**
37
+ * Check if an element has a valid queryContext method (returns non-any, non-unknown type)
38
+ */
39
+ type HasValidQueryContext<E> = E extends {
40
+ queryContext: (...args: any[]) => infer R;
41
+ } ? unknown extends R ? false : R extends Record<string, any> ? true : false : false;
42
+ /**
43
+ * Check if an element has a valid mutateContext method (returns non-any, non-unknown type)
44
+ */
45
+ type HasValidMutateContext<E> = E extends {
46
+ mutateContext: (...args: any[]) => infer R;
47
+ } ? unknown extends R ? false : R extends ((...args: any[]) => any) | Record<string, any> ? true : false : false;
48
+ /**
49
+ * Check if an element is a valid context element (has name and at least one valid context method)
50
+ * Elements without queryContext or mutateContext (like events, listeners) are still valid
51
+ */
52
+ type IsValidContextElement<E> = E extends ArcContextElement<infer Name> ? Name extends string ? true : false : false;
53
+ /**
54
+ * Filter type that keeps only valid context elements
55
+ * Invalid elements are converted to never and filtered out
56
+ */
57
+ type FilterValidElements<Elements extends readonly any[]> = {
58
+ [K in keyof Elements]: IsValidContextElement<Elements[K]> extends true ? Elements[K] : never;
59
+ };
60
+ /**
61
+ * Flatten and filter elements from multiple contexts
62
+ */
63
+ type MergedElements<Contexts extends ArcContextAny[]> = FilterValidElements<Contexts[number]["elements"]>;
64
+ /**
65
+ * Debug type that shows which elements have valid queryContext
66
+ * Hover over this type to see: valid elements show their name, invalid show "⚠️ NO_QUERY: name"
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * // Use to debug which elements are missing queryContext:
71
+ * type Debug = DebugQueryElements<typeof myContext>;
72
+ * // Hover over Debug to see which elements are valid/invalid
73
+ * ```
74
+ */
75
+ export type DebugQueryElements<C extends ArcContextAny> = {
76
+ [Element in C["elements"][number] as HasValidQueryContext<Element> extends true ? Element["name"] : `⚠️ NO_QUERY: ${Element["name"]}`]: Element extends {
77
+ queryContext: (...args: any[]) => infer R;
78
+ } ? R : "no queryContext method";
79
+ };
80
+ /**
81
+ * Debug type that shows which elements have valid mutateContext
82
+ * Hover over this type to see: valid elements show their name, invalid show "⚠️ NO_MUTATE: name"
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * // Use to debug which elements are missing mutateContext:
87
+ * type Debug = DebugMutateElements<typeof myContext>;
88
+ * // Hover over Debug to see which elements are valid/invalid
89
+ * ```
90
+ */
91
+ export type DebugMutateElements<C extends ArcContextAny> = {
92
+ [Element in C["elements"][number] as HasValidMutateContext<Element> extends true ? Element["name"] : `⚠️ NO_MUTATE: ${Element["name"]}`]: Element extends {
93
+ mutateContext: (...args: any[]) => infer R;
94
+ } ? R : "no mutateContext method";
95
+ };
96
+ /**
97
+ * Combined debug type showing both query and mutate status for all elements
98
+ * Use this to get a complete picture of your context's type health
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * // Use to debug all elements:
103
+ * type Debug = DebugContextElements<typeof myContext>;
104
+ * // Hover over Debug to see status of all elements
105
+ * ```
106
+ */
107
+ export type DebugContextElements<C extends ArcContextAny> = {
108
+ [Element in C["elements"][number] as Element["name"]]: {
109
+ name: Element["name"];
110
+ hasQueryContext: HasValidQueryContext<Element>;
111
+ hasMutateContext: HasValidMutateContext<Element>;
112
+ queryContextType: Element extends {
113
+ queryContext: (...args: any[]) => infer R;
114
+ } ? R : never;
115
+ mutateContextType: Element extends {
116
+ mutateContext: (...args: any[]) => infer R;
117
+ } ? R : never;
118
+ };
119
+ };
120
+ /**
121
+ * Extract only the elements that have issues (no valid query or mutate context when expected)
122
+ * This filters to show only problematic elements
123
+ */
124
+ export type DebugInvalidElements<C extends ArcContextAny> = {
125
+ [Element in C["elements"][number] as HasValidQueryContext<Element> extends false ? HasValidMutateContext<Element> extends false ? Element["name"] : never : never]: {
126
+ issue: "Element has neither valid queryContext nor mutateContext";
127
+ };
128
+ };
36
129
  /**
37
130
  * Merge multiple contexts into one
38
131
  *
@@ -43,10 +136,19 @@ export declare function context<const Elements extends ArcContextElement<any>[]>
43
136
  * ```typescript
44
137
  * const mergedContext = contextMerge(authContext, taskContext, chatContext);
45
138
  * ```
139
+ *
140
+ * @example Debug type issues
141
+ * ```typescript
142
+ * // If useQuery or useCommands lose types, debug with:
143
+ * type Debug = DebugContextElements<typeof mergedContext>;
144
+ * // Or for just invalid elements:
145
+ * type Invalid = DebugInvalidElements<typeof mergedContext>;
146
+ * ```
46
147
  */
47
- export declare function contextMerge<const Contexts extends ArcContextAny[]>(...contexts: Contexts): ArcContext<Contexts[number]["elements"]>;
148
+ export declare function contextMerge<const Contexts extends ArcContextAny[]>(...contexts: Contexts): ArcContext<MergedElements<Contexts>>;
48
149
  /**
49
150
  * Type alias for any context (used in collections)
50
151
  */
51
152
  export type ArcContextAny = ArcContext<ArcContextElementAny[]>;
153
+ export {};
52
154
  //# sourceMappingURL=context.d.ts.map
@@ -1,2 +1,2 @@
1
- export { ArcContext, context, contextMerge, type ArcContextAny, } from "./context";
1
+ export { ArcContext, context, contextMerge, type ArcContextAny, type DebugContextElements, type DebugInvalidElements, type DebugMutateElements, type DebugQueryElements, } from "./context";
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -3,8 +3,10 @@
3
3
  *
4
4
  * Provides dependency injection and element registration
5
5
  */
6
- export * from "./context-element";
7
6
  export * from "./command";
7
+ export * from "./context-element";
8
8
  export * from "./event";
9
+ export * from "./listener";
10
+ export * from "./route";
9
11
  export * from "./view";
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ export * from "./listener";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,170 @@
1
+ import type { ModelAdapters } from "../../model/model-adapters";
2
+ import type { Merge } from "../../utils";
3
+ import { ArcContextElement, type ArcEnvironment } from "../context-element";
4
+ import type { ArcEventAny } from "../event/event";
5
+ import type { ArcEventInstance } from "../event/instance";
6
+ /**
7
+ * Listener Data - Configuration for a listener
8
+ */
9
+ export interface ArcListenerData {
10
+ name: string;
11
+ description?: string;
12
+ eventElements: ArcEventAny[];
13
+ queryElements: ArcContextElement<any>[];
14
+ mutationElements: ArcContextElement<any>[];
15
+ handler?: ArcListenerHandler<any, any>;
16
+ isAsync: boolean;
17
+ }
18
+ /**
19
+ * Listener Context - Available to listener handlers
20
+ */
21
+ export type ArcListenerContext<QueryElements extends ArcContextElement<any>[], MutationElements extends ArcContextElement<any>[]> = {
22
+ [K in QueryElements[number] as K["name"]]: K extends {
23
+ queryContext: (adapters: ModelAdapters) => infer R;
24
+ } ? R : never;
25
+ } & {
26
+ [K in MutationElements[number] as K["name"]]: K extends {
27
+ mutateContext: (adapters: ModelAdapters) => infer R;
28
+ } ? R : never;
29
+ } & {
30
+ get: <T extends ArcContextElement<any>>(element: T) => T extends {
31
+ queryContext: (adapters: ModelAdapters) => infer R;
32
+ } ? R : T extends {
33
+ mutateContext: (adapters: ModelAdapters) => infer R;
34
+ } ? R : never;
35
+ $auth?: {
36
+ params: any;
37
+ tokenName: string;
38
+ };
39
+ };
40
+ /**
41
+ * Listener Handler - Function that handles events
42
+ */
43
+ export type ArcListenerHandler<Context, EventElements extends ArcEventAny[]> = (ctx: Context, event: ArcEventInstance<EventElements[number]>) => Promise<void> | void;
44
+ /**
45
+ * Arc Listener - Reactive side effect triggered by events
46
+ *
47
+ * Listeners react to events and can:
48
+ * - Query state through query elements (views)
49
+ * - Mutate state through mutation elements (events, commands)
50
+ * - Run synchronously (blocking) or asynchronously (fire-and-forget)
51
+ *
52
+ * Listeners only run on the server.
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const notifyOnTaskCreated = listener("notifyOnTaskCreated")
57
+ * .listenTo([taskCreatedEvent])
58
+ * .query([usersView])
59
+ * .mutate([notificationSentEvent])
60
+ * .handle(async (ctx, event) => {
61
+ * const user = await ctx.usersView.findOne({ _id: event.payload.assignedTo });
62
+ * if (user) {
63
+ * await ctx.notificationSentEvent.emit({ userId: user._id, message: "New task!" });
64
+ * }
65
+ * });
66
+ * ```
67
+ */
68
+ export declare class ArcListener<const Data extends ArcListenerData> extends ArcContextElement<Data["name"]> {
69
+ private readonly data;
70
+ private unsubscribers;
71
+ constructor(data: Data);
72
+ /**
73
+ * Set listener description for documentation
74
+ */
75
+ description<const Desc extends string>(description: Desc): ArcListener<Merge<Data, {
76
+ description: Desc;
77
+ }>>;
78
+ /**
79
+ * Specify which events this listener reacts to
80
+ *
81
+ * @param events - Array of event elements to listen to
82
+ */
83
+ listenTo<const Events extends ArcEventAny[]>(events: Events): ArcListener<Merge<Data, {
84
+ eventElements: Events;
85
+ }>>;
86
+ /**
87
+ * Add query elements (views) that this listener needs to read from
88
+ *
89
+ * @param elements - Array of view elements to query
90
+ */
91
+ query<const Elements extends ArcContextElement<any>[]>(elements: Elements): ArcListener<Merge<Data, {
92
+ queryElements: Elements;
93
+ }>>;
94
+ /**
95
+ * Add mutation elements (events, commands) that this listener needs to modify state
96
+ *
97
+ * @param elements - Array of event/command elements to mutate with
98
+ */
99
+ mutate<const Elements extends ArcContextElement<any>[]>(elements: Elements): ArcListener<Merge<Data, {
100
+ mutationElements: Elements;
101
+ }>>;
102
+ /**
103
+ * Mark listener as async (fire-and-forget)
104
+ * Async listeners don't block event processing
105
+ */
106
+ async(): ArcListener<Merge<Data, {
107
+ isAsync: true;
108
+ }>>;
109
+ /**
110
+ * Set the handler function for this listener
111
+ *
112
+ * @param handler - Function that handles events
113
+ */
114
+ handle<Handler extends ArcListenerHandler<ArcListenerContext<Data["queryElements"], Data["mutationElements"]>, Data["eventElements"]>>(handler: Handler): ArcListener<Merge<Data, {
115
+ handler: Handler;
116
+ }>>;
117
+ /**
118
+ * Get the events this listener is subscribed to
119
+ */
120
+ get eventElements(): ArcEventAny[];
121
+ /**
122
+ * Check if listener is async
123
+ */
124
+ get isAsync(): boolean;
125
+ /**
126
+ * Initialize listener - subscribe to events
127
+ * Only runs on server
128
+ */
129
+ init(environment: ArcEnvironment, adapters: ModelAdapters): Promise<void>;
130
+ /**
131
+ * Handle an incoming event
132
+ */
133
+ private handleEvent;
134
+ /**
135
+ * Build listener context with access to query and mutation elements
136
+ */
137
+ private buildListenerContext;
138
+ /**
139
+ * Cleanup - unsubscribe from all events
140
+ */
141
+ destroy(): void;
142
+ }
143
+ /**
144
+ * Create a new listener with the given name
145
+ *
146
+ * @param name - Unique listener name
147
+ * @returns New listener instance ready for configuration
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * const myListener = listener("myListener")
152
+ * .listenTo([someEvent])
153
+ * .mutate([anotherEvent])
154
+ * .handle(async (ctx, event) => {
155
+ * await ctx.anotherEvent.emit({ ... });
156
+ * });
157
+ * ```
158
+ */
159
+ export declare function listener<const Name extends string>(name: Name): ArcListener<{
160
+ readonly name: Name;
161
+ readonly eventElements: [];
162
+ readonly queryElements: [];
163
+ readonly mutationElements: [];
164
+ readonly isAsync: false;
165
+ }>;
166
+ /**
167
+ * Type alias for any listener (used in collections)
168
+ */
169
+ export type ArcListenerAny = ArcListener<any>;
170
+ //# sourceMappingURL=listener.d.ts.map
@@ -0,0 +1,3 @@
1
+ export * from "./route";
2
+ export * from "./route-data";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,42 @@
1
+ import type { ArcTokenAny } from "../../token/token";
2
+ import type { ArcContextElement } from "../context-element";
3
+ /**
4
+ * HTTP methods supported by routes
5
+ */
6
+ export type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
7
+ /**
8
+ * Route handler function
9
+ */
10
+ export type RouteHandler<Ctx> = (ctx: Ctx, request: Request, params: Record<string, string>, url: URL) => Promise<Response> | Response;
11
+ /**
12
+ * Route handlers object - maps HTTP methods to handlers
13
+ */
14
+ export type RouteHandlers<Ctx> = {
15
+ [Method in HttpMethod]?: RouteHandler<Ctx>;
16
+ };
17
+ /**
18
+ * Protection check function for routes
19
+ * Returns true to allow, false to deny
20
+ */
21
+ export type RouteProtectionCheck<T extends ArcTokenAny> = (tokenInstance: ReturnType<T["create"]>) => boolean | Promise<boolean>;
22
+ /**
23
+ * Route protection configuration
24
+ */
25
+ export type RouteProtection = {
26
+ token: ArcTokenAny;
27
+ check: RouteProtectionCheck<any>;
28
+ };
29
+ /**
30
+ * Route data configuration
31
+ */
32
+ export type ArcRouteData = {
33
+ name: string;
34
+ path?: string;
35
+ description?: string;
36
+ queryElements: ArcContextElement<any>[];
37
+ mutationElements: ArcContextElement<any>[];
38
+ handlers: RouteHandlers<any>;
39
+ protections: RouteProtection[];
40
+ isPublic: boolean;
41
+ };
42
+ //# sourceMappingURL=route-data.d.ts.map
@@ -0,0 +1,163 @@
1
+ import type { ModelAdapters } from "../../model/model-adapters";
2
+ import type { ArcTokenAny } from "../../token/token";
3
+ import type { TokenInstanceAny } from "../../token/token-instance";
4
+ import type { Merge } from "../../utils";
5
+ import { ArcContextElement } from "../context-element";
6
+ import type { ArcRouteData, HttpMethod, RouteHandler, RouteHandlers, RouteProtectionCheck } from "./route-data";
7
+ /**
8
+ * Route context passed to handlers
9
+ */
10
+ export type ArcRouteContext<QueryElements extends ArcContextElement<any>[], MutationElements extends ArcContextElement<any>[]> = {
11
+ [K in QueryElements[number]["name"]]: QueryElements[number] extends {
12
+ name: K;
13
+ queryContext: (...args: any[]) => infer R;
14
+ } ? R : never;
15
+ } & {
16
+ [K in MutationElements[number]["name"]]: MutationElements[number] extends {
17
+ name: K;
18
+ mutateContext: (...args: any[]) => infer R;
19
+ } ? R : never;
20
+ } & {
21
+ get: <T extends ArcContextElement<any>>(element: T) => T extends {
22
+ queryContext: (...args: any[]) => infer R;
23
+ } ? R : T extends {
24
+ mutateContext: (...args: any[]) => infer R;
25
+ } ? R : never;
26
+ $auth?: {
27
+ params: Record<string, any>;
28
+ tokenName: string;
29
+ };
30
+ };
31
+ /**
32
+ * Arc Route - Custom HTTP endpoint handler
33
+ *
34
+ * Routes allow defining custom HTTP endpoints that can:
35
+ * - Handle GET, POST, PUT, DELETE, PATCH requests
36
+ * - Access views (query) and events/commands (mutate)
37
+ * - Be public or protected by tokens
38
+ * - Use path parameters (e.g., /users/:userId)
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const stripeWebhook = route("stripeWebhook")
43
+ * .path("/stripe/webhook")
44
+ * .public()
45
+ * .mutate([orderPaidEvent])
46
+ * .handle({
47
+ * POST: async (ctx, req) => {
48
+ * const body = await req.json();
49
+ * await ctx.orderPaidEvent.emit({ ... });
50
+ * return new Response("OK");
51
+ * }
52
+ * });
53
+ * ```
54
+ */
55
+ export declare class ArcRoute<const Data extends ArcRouteData> extends ArcContextElement<Data["name"]> {
56
+ private readonly data;
57
+ constructor(data: Data);
58
+ /**
59
+ * Set route description
60
+ */
61
+ description<const Desc extends string>(description: Desc): ArcRoute<Merge<Data, {
62
+ description: Desc;
63
+ }>>;
64
+ /**
65
+ * Set route path pattern
66
+ * Supports path parameters like /users/:userId
67
+ * Path will be prefixed with /route automatically
68
+ */
69
+ path<const P extends string>(path: P): ArcRoute<Merge<Data, {
70
+ path: P;
71
+ }>>;
72
+ /**
73
+ * Mark route as public (no authentication required)
74
+ */
75
+ public(): ArcRoute<Merge<Data, {
76
+ isPublic: true;
77
+ }>>;
78
+ /**
79
+ * Add query elements (views) that this route can read from
80
+ */
81
+ query<const Elements extends ArcContextElement<any>[]>(elements: Elements): ArcRoute<Merge<Data, {
82
+ queryElements: Elements;
83
+ }>>;
84
+ /**
85
+ * Add mutation elements (events, commands) that this route can use
86
+ */
87
+ mutate<const Elements extends ArcContextElement<any>[]>(elements: Elements): ArcRoute<Merge<Data, {
88
+ mutationElements: Elements;
89
+ }>>;
90
+ /**
91
+ * Add token-based protection to this route
92
+ * Check function returns true to allow, false to deny
93
+ * Token params available in ctx.$auth
94
+ */
95
+ protectBy<T extends ArcTokenAny>(token: T, check: RouteProtectionCheck<T>): ArcRoute<Data>;
96
+ /**
97
+ * Set route handlers for HTTP methods
98
+ */
99
+ handle<Handlers extends RouteHandlers<ArcRouteContext<Data["queryElements"], Data["mutationElements"]>>>(handlers: Handlers): ArcRoute<Merge<Data, {
100
+ handlers: Handlers;
101
+ }>>;
102
+ /**
103
+ * Get the route path (without /route prefix)
104
+ */
105
+ get routePath(): string;
106
+ /**
107
+ * Get the full route path (with /route prefix)
108
+ */
109
+ get fullPath(): string;
110
+ /**
111
+ * Check if route is public
112
+ */
113
+ get isPublic(): boolean;
114
+ /**
115
+ * Check if route has protections
116
+ */
117
+ get hasProtections(): boolean;
118
+ /**
119
+ * Get all protection configurations
120
+ */
121
+ get protections(): import("./route-data").RouteProtection[];
122
+ /**
123
+ * Get handler for a specific HTTP method
124
+ */
125
+ getHandler(method: HttpMethod): RouteHandler<any> | undefined;
126
+ /**
127
+ * Check if a pathname matches this route's path pattern
128
+ * Returns match result with extracted params
129
+ */
130
+ matchesPath(pathname: string): {
131
+ matches: boolean;
132
+ params: Record<string, string>;
133
+ };
134
+ /**
135
+ * Verify all protections pass for given token instances
136
+ */
137
+ verifyProtections(tokens: TokenInstanceAny[]): Promise<boolean>;
138
+ /**
139
+ * Build route context with access to query and mutation elements
140
+ */
141
+ buildContext(adapters: ModelAdapters, authParams?: {
142
+ params: Record<string, any>;
143
+ tokenName: string;
144
+ }): ArcRouteContext<Data["queryElements"], Data["mutationElements"]>;
145
+ }
146
+ /**
147
+ * Create a new route with the given name
148
+ */
149
+ export declare function route<const Name extends string>(name: Name): ArcRoute<{
150
+ name: Name;
151
+ path: undefined;
152
+ description: undefined;
153
+ queryElements: [];
154
+ mutationElements: [];
155
+ handlers: {};
156
+ protections: [];
157
+ isPublic: false;
158
+ }>;
159
+ /**
160
+ * Type alias for any route
161
+ */
162
+ export type ArcRouteAny = ArcRoute<any>;
163
+ //# sourceMappingURL=route.d.ts.map
@@ -4,15 +4,14 @@ import type { ArcTokenAny } from "../../token/token";
4
4
  import type { ArcContextElement } from "../context-element";
5
5
  /**
6
6
  * Protection config for views
7
- * Defines read/write access conditions based on token params
7
+ * Defines read access conditions based on token params
8
+ * Write protection is handled by event protections, not view protections
8
9
  */
9
- export type ViewProtectionConfig = {
10
- read: WhereCondition | false;
11
- write: WhereCondition | false;
12
- };
10
+ export type ViewProtectionConfig = WhereCondition | false;
13
11
  /**
14
12
  * Protection function for views
15
- * Receives token params and returns read/write conditions
13
+ * Receives token params and returns read conditions (where clause)
14
+ * Return false to deny access entirely
16
15
  */
17
16
  export type ViewProtectionFn<TokenParams> = (params: TokenParams) => ViewProtectionConfig;
18
17
  /**