@arcote.tech/arc 0.3.1 → 0.3.2
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/adapters/event-publisher.d.ts +18 -0
- package/dist/adapters/index.d.ts +3 -0
- package/dist/adapters/query-wire.d.ts +34 -0
- package/dist/adapters/wire.d.ts +9 -1
- package/dist/context/context.d.ts +104 -2
- package/dist/context/index.d.ts +1 -1
- package/dist/context-element/index.d.ts +3 -1
- package/dist/context-element/listener/index.d.ts +2 -0
- package/dist/context-element/listener/listener.d.ts +170 -0
- package/dist/context-element/route/index.d.ts +3 -0
- package/dist/context-element/route/route-data.d.ts +42 -0
- package/dist/context-element/route/route.d.ts +163 -0
- package/dist/context-element/view/view-data.d.ts +5 -6
- package/dist/context-element/view/view.d.ts +15 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.js +725 -69
- package/dist/model/live-query/live-query.d.ts +2 -1
- package/dist/model/model-adapters.d.ts +5 -0
- package/dist/streaming/index.d.ts +6 -0
- package/dist/streaming/streaming-event-publisher.d.ts +51 -0
- package/dist/streaming/streaming-live-query.d.ts +23 -0
- package/dist/streaming/streaming-query-cache.d.ts +57 -0
- package/dist/token/index.d.ts +2 -5
- package/package.json +1 -1
|
@@ -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
|
/**
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -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
|
package/dist/adapters/wire.d.ts
CHANGED
|
@@ -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:
|
|
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
|
|
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
|
package/dist/context/index.d.ts
CHANGED
|
@@ -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,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,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
|
|
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
|
|
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
|
/**
|