@syncular/relay 0.0.1-60

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.
Files changed (68) hide show
  1. package/dist/client-role/forward-engine.d.ts +63 -0
  2. package/dist/client-role/forward-engine.d.ts.map +1 -0
  3. package/dist/client-role/forward-engine.js +263 -0
  4. package/dist/client-role/forward-engine.js.map +1 -0
  5. package/dist/client-role/index.d.ts +9 -0
  6. package/dist/client-role/index.d.ts.map +1 -0
  7. package/dist/client-role/index.js +9 -0
  8. package/dist/client-role/index.js.map +1 -0
  9. package/dist/client-role/pull-engine.d.ts +70 -0
  10. package/dist/client-role/pull-engine.d.ts.map +1 -0
  11. package/dist/client-role/pull-engine.js +233 -0
  12. package/dist/client-role/pull-engine.js.map +1 -0
  13. package/dist/client-role/sequence-mapper.d.ts +65 -0
  14. package/dist/client-role/sequence-mapper.d.ts.map +1 -0
  15. package/dist/client-role/sequence-mapper.js +161 -0
  16. package/dist/client-role/sequence-mapper.js.map +1 -0
  17. package/dist/index.d.ts +37 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +44 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/migrate.d.ts +18 -0
  22. package/dist/migrate.d.ts.map +1 -0
  23. package/dist/migrate.js +99 -0
  24. package/dist/migrate.js.map +1 -0
  25. package/dist/mode-manager.d.ts +60 -0
  26. package/dist/mode-manager.d.ts.map +1 -0
  27. package/dist/mode-manager.js +114 -0
  28. package/dist/mode-manager.js.map +1 -0
  29. package/dist/realtime.d.ts +102 -0
  30. package/dist/realtime.d.ts.map +1 -0
  31. package/dist/realtime.js +305 -0
  32. package/dist/realtime.js.map +1 -0
  33. package/dist/relay.d.ts +188 -0
  34. package/dist/relay.d.ts.map +1 -0
  35. package/dist/relay.js +315 -0
  36. package/dist/relay.js.map +1 -0
  37. package/dist/schema.d.ts +158 -0
  38. package/dist/schema.d.ts.map +1 -0
  39. package/dist/schema.js +7 -0
  40. package/dist/schema.js.map +1 -0
  41. package/dist/server-role/index.d.ts +54 -0
  42. package/dist/server-role/index.d.ts.map +1 -0
  43. package/dist/server-role/index.js +198 -0
  44. package/dist/server-role/index.js.map +1 -0
  45. package/dist/server-role/pull.d.ts +25 -0
  46. package/dist/server-role/pull.d.ts.map +1 -0
  47. package/dist/server-role/pull.js +24 -0
  48. package/dist/server-role/pull.js.map +1 -0
  49. package/dist/server-role/push.d.ts +27 -0
  50. package/dist/server-role/push.d.ts.map +1 -0
  51. package/dist/server-role/push.js +98 -0
  52. package/dist/server-role/push.js.map +1 -0
  53. package/package.json +61 -0
  54. package/src/__tests__/relay.test.ts +464 -0
  55. package/src/bun-types.d.ts +50 -0
  56. package/src/client-role/forward-engine.ts +352 -0
  57. package/src/client-role/index.ts +9 -0
  58. package/src/client-role/pull-engine.ts +301 -0
  59. package/src/client-role/sequence-mapper.ts +201 -0
  60. package/src/index.ts +50 -0
  61. package/src/migrate.ts +113 -0
  62. package/src/mode-manager.ts +142 -0
  63. package/src/realtime.ts +370 -0
  64. package/src/relay.ts +421 -0
  65. package/src/schema.ts +171 -0
  66. package/src/server-role/index.ts +342 -0
  67. package/src/server-role/pull.ts +37 -0
  68. package/src/server-role/push.ts +130 -0
package/dist/relay.js ADDED
@@ -0,0 +1,315 @@
1
+ /**
2
+ * @syncular/relay - Relay Server
3
+ *
4
+ * An edge relay server that acts as a local server to nearby clients
5
+ * while simultaneously acting as a client to the main server.
6
+ *
7
+ * Enables offline-first architectures where local network devices
8
+ * continue syncing when internet is lost.
9
+ */
10
+ import { sql } from 'kysely';
11
+ import { ForwardEngine } from './client-role/forward-engine';
12
+ import { PullEngine } from './client-role/pull-engine';
13
+ import { SequenceMapper } from './client-role/sequence-mapper';
14
+ import { ensureRelaySchema } from './migrate';
15
+ import { ModeManager } from './mode-manager';
16
+ import { RelayRealtime } from './realtime';
17
+ /**
18
+ * Relay server that acts as an edge relay between local clients and a main server.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * import { createRelayServer } from '@syncular/relay';
23
+ * import { createSqliteServerDialect } from '@syncular/server-dialect-sqlite';
24
+ *
25
+ * const relay = createRelayServer({
26
+ * db: sqliteDb,
27
+ * dialect: createSqliteServerDialect(),
28
+ * mainServerTransport: createHttpTransport({ baseUrl: 'https://main.example.com/sync' }),
29
+ * mainServerClientId: 'relay-branch-001',
30
+ * mainServerActorId: 'relay-service',
31
+ * tables: ['tasks', 'projects'],
32
+ * scopes: { project_id: 'acme' },
33
+ * shapes: shapeRegistry,
34
+ * });
35
+ *
36
+ * // Mount routes for local clients
37
+ * app.route('/sync', relay.getRoutes());
38
+ *
39
+ * // Start background sync with main
40
+ * await relay.start();
41
+ *
42
+ * // Events
43
+ * relay.on('modeChange', (mode) => console.log(mode));
44
+ * relay.on('forwardConflict', (conflict) => handleConflict(conflict));
45
+ * ```
46
+ */
47
+ export class RelayServer {
48
+ db;
49
+ dialect;
50
+ mainServerTransport;
51
+ mainServerClientId;
52
+ mainServerActorId;
53
+ tables;
54
+ scopes;
55
+ shapes;
56
+ modeManager;
57
+ sequenceMapper;
58
+ forwardEngine;
59
+ pullEngine;
60
+ realtime;
61
+ eventHandlers = new Map();
62
+ pruneIntervalMs;
63
+ pruneMaxAgeMs;
64
+ lastPruneAtMs = 0;
65
+ pruneInFlight = null;
66
+ started = false;
67
+ schemaInitialized = false;
68
+ routes = null;
69
+ constructor(options) {
70
+ this.db = options.db;
71
+ this.dialect = options.dialect;
72
+ this.mainServerTransport = options.mainServerTransport;
73
+ this.mainServerClientId = options.mainServerClientId;
74
+ this.mainServerActorId = options.mainServerActorId;
75
+ this.tables = options.tables;
76
+ this.scopes = options.scopes;
77
+ this.shapes = options.shapes;
78
+ this.pruneIntervalMs = options.pruneIntervalMs ?? 3600000;
79
+ this.pruneMaxAgeMs = options.pruneMaxAgeMs ?? 7 * 24 * 60 * 60 * 1000;
80
+ // Initialize mode manager
81
+ this.modeManager = new ModeManager({
82
+ healthCheckIntervalMs: options.healthCheckIntervalMs ?? 30000,
83
+ onModeChange: (mode) => this.emit('modeChange', mode),
84
+ });
85
+ // Initialize sequence mapper
86
+ this.sequenceMapper = new SequenceMapper({
87
+ db: this.db,
88
+ });
89
+ // Initialize realtime manager for local clients
90
+ this.realtime = new RelayRealtime({
91
+ heartbeatIntervalMs: options.heartbeatIntervalMs ?? 30000,
92
+ });
93
+ // Initialize forward engine (forwards local commits to main)
94
+ this.forwardEngine = new ForwardEngine({
95
+ db: this.db,
96
+ transport: this.mainServerTransport,
97
+ clientId: this.mainServerClientId,
98
+ sequenceMapper: this.sequenceMapper,
99
+ retryIntervalMs: options.forwardRetryIntervalMs ?? 5000,
100
+ onConflict: (conflict) => this.emit('forwardConflict', conflict),
101
+ onError: (error) => this.emit('error', error),
102
+ });
103
+ // Initialize pull engine (pulls changes from main)
104
+ this.pullEngine = new PullEngine({
105
+ db: this.db,
106
+ dialect: this.dialect,
107
+ transport: this.mainServerTransport,
108
+ clientId: this.mainServerClientId,
109
+ tables: this.tables,
110
+ scopes: this.scopes,
111
+ shapes: this.shapes,
112
+ sequenceMapper: this.sequenceMapper,
113
+ realtime: this.realtime,
114
+ intervalMs: options.pullIntervalMs ?? 10000,
115
+ onError: (error) => this.emit('error', error),
116
+ onPullComplete: async () => {
117
+ await this.maybePruneRelay();
118
+ },
119
+ });
120
+ }
121
+ /**
122
+ * Subscribe to relay events.
123
+ */
124
+ on(event, handler) {
125
+ let handlers = this.eventHandlers.get(event);
126
+ if (!handlers) {
127
+ handlers = new Set();
128
+ this.eventHandlers.set(event, handlers);
129
+ }
130
+ handlers.add(handler);
131
+ return () => {
132
+ handlers?.delete(handler);
133
+ };
134
+ }
135
+ /**
136
+ * Get the current mode (online/offline/reconnecting).
137
+ */
138
+ getMode() {
139
+ return this.modeManager.getMode();
140
+ }
141
+ /**
142
+ * Get the tables this relay subscribes to.
143
+ */
144
+ getTables() {
145
+ return this.tables;
146
+ }
147
+ /**
148
+ * Get the scope values for subscriptions.
149
+ */
150
+ getScopes() {
151
+ return this.scopes;
152
+ }
153
+ /**
154
+ * Get the realtime manager for WebSocket connections.
155
+ */
156
+ getRealtime() {
157
+ return this.realtime;
158
+ }
159
+ /**
160
+ * Start the relay server background processes.
161
+ *
162
+ * This initializes the database schema and starts:
163
+ * - Forward engine (sends local commits to main)
164
+ * - Pull engine (receives changes from main)
165
+ * - Mode manager (tracks online/offline state)
166
+ */
167
+ async start() {
168
+ if (this.started)
169
+ return;
170
+ // Initialize schema if needed
171
+ if (!this.schemaInitialized) {
172
+ await ensureRelaySchema(this.db, this.dialect);
173
+ this.schemaInitialized = true;
174
+ }
175
+ this.started = true;
176
+ // Start background processes
177
+ this.modeManager.start(async () => {
178
+ // Health check: try an empty pull
179
+ try {
180
+ await this.mainServerTransport.sync({
181
+ clientId: this.mainServerClientId,
182
+ pull: {
183
+ subscriptions: [],
184
+ limitCommits: 0,
185
+ },
186
+ });
187
+ return true;
188
+ }
189
+ catch {
190
+ return false;
191
+ }
192
+ });
193
+ this.forwardEngine.start();
194
+ this.pullEngine.start();
195
+ }
196
+ /**
197
+ * Stop the relay server background processes.
198
+ */
199
+ async stop() {
200
+ if (!this.started)
201
+ return;
202
+ this.started = false;
203
+ this.modeManager.stop();
204
+ this.forwardEngine.stop();
205
+ this.pullEngine.stop();
206
+ this.realtime.closeAll();
207
+ }
208
+ /**
209
+ * Manually trigger a forward cycle (useful for testing).
210
+ */
211
+ async forwardOnce() {
212
+ return this.forwardEngine.forwardOnce();
213
+ }
214
+ /**
215
+ * Manually trigger a pull cycle (useful for testing).
216
+ */
217
+ async pullOnce() {
218
+ return this.pullEngine.pullOnce();
219
+ }
220
+ /**
221
+ * Prune old relay data (sequence mappings, forwarded outbox, resolved conflicts).
222
+ */
223
+ async pruneRelay(options) {
224
+ const maxAgeMs = options?.maxAgeMs ?? this.pruneMaxAgeMs;
225
+ const threshold = Date.now() - maxAgeMs;
226
+ const deletedMappings = await this.sequenceMapper.pruneOldMappings(maxAgeMs);
227
+ const outboxResult = await sql `
228
+ delete from ${sql.table('relay_forward_outbox')}
229
+ where status in ('forwarded', 'failed')
230
+ and updated_at < ${threshold}
231
+ `.execute(this.db);
232
+ const deletedOutbox = Number(outboxResult.numAffectedRows ?? 0);
233
+ const conflictsResult = await sql `
234
+ delete from ${sql.table('relay_forward_conflicts')}
235
+ where resolved_at is not null
236
+ and resolved_at < ${threshold}
237
+ `.execute(this.db);
238
+ const deletedConflicts = Number(conflictsResult.numAffectedRows ?? 0);
239
+ return { deletedMappings, deletedOutbox, deletedConflicts };
240
+ }
241
+ /**
242
+ * Rate-limited pruning. Skips if called within `pruneIntervalMs` of last prune.
243
+ * Returns zero counts if skipped or if pruning is disabled.
244
+ */
245
+ async maybePruneRelay() {
246
+ if (this.pruneIntervalMs <= 0) {
247
+ return { deletedMappings: 0, deletedOutbox: 0, deletedConflicts: 0 };
248
+ }
249
+ const now = Date.now();
250
+ if (now - this.lastPruneAtMs < this.pruneIntervalMs) {
251
+ return { deletedMappings: 0, deletedOutbox: 0, deletedConflicts: 0 };
252
+ }
253
+ if (this.pruneInFlight)
254
+ return this.pruneInFlight;
255
+ this.pruneInFlight = (async () => {
256
+ try {
257
+ const result = await this.pruneRelay();
258
+ this.lastPruneAtMs = Date.now();
259
+ return result;
260
+ }
261
+ finally {
262
+ this.pruneInFlight = null;
263
+ }
264
+ })();
265
+ return this.pruneInFlight;
266
+ }
267
+ /**
268
+ * Get Hono routes for local clients.
269
+ *
270
+ * Mount these routes to serve local sync clients:
271
+ * - POST /pull
272
+ * - POST /push
273
+ * - GET /realtime (WebSocket)
274
+ */
275
+ getRoutes() {
276
+ if (this.routes)
277
+ return this.routes;
278
+ // Lazy import to avoid requiring hono as a hard dependency
279
+ const { createRelayRoutes } = require('./server-role');
280
+ const routes = createRelayRoutes({
281
+ db: this.db,
282
+ dialect: this.dialect,
283
+ shapes: this.shapes,
284
+ realtime: this.realtime,
285
+ onCommit: async (localCommitSeq, affectedTables) => {
286
+ // Notify local clients via WebSocket
287
+ this.realtime.notifyScopeKeys(affectedTables, localCommitSeq);
288
+ // Wake up forward engine to send to main
289
+ this.forwardEngine.wakeUp();
290
+ },
291
+ });
292
+ this.routes = routes;
293
+ return routes;
294
+ }
295
+ emit(event, ...args) {
296
+ const handlers = this.eventHandlers.get(event);
297
+ if (!handlers)
298
+ return;
299
+ for (const handler of handlers) {
300
+ try {
301
+ handler(...args);
302
+ }
303
+ catch (err) {
304
+ console.error(`Error in ${event} handler:`, err);
305
+ }
306
+ }
307
+ }
308
+ }
309
+ /**
310
+ * Create a new relay server instance.
311
+ */
312
+ export function createRelayServer(options) {
313
+ return new RelayServer(options);
314
+ }
315
+ //# sourceMappingURL=relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.js","sourceRoot":"","sources":["../src/relay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * @syncular/relay - Database schema types
3
+ *
4
+ * Relay-specific tables for edge relay servers.
5
+ */
6
+ import type { SyncCoreDb } from '@syncular/server';
7
+ import type { Generated } from 'kysely';
8
+ /**
9
+ * Forward outbox status for commits awaiting forwarding to main server.
10
+ */
11
+ export type RelayForwardOutboxStatus = 'pending' | 'forwarding' | 'forwarded' | 'failed';
12
+ /**
13
+ * Sequence map status for tracking local to main commit mapping.
14
+ */
15
+ export type RelaySequenceMapStatus = 'pending' | 'forwarded' | 'confirmed';
16
+ /**
17
+ * Forward outbox - Queue for commits to forward to main server.
18
+ *
19
+ * When local clients push to the relay, commits are stored here
20
+ * for subsequent forwarding to the main server.
21
+ */
22
+ interface RelayForwardOutboxTable {
23
+ /** Unique identifier for this outbox entry */
24
+ id: string;
25
+ /** Local commit sequence assigned by the relay */
26
+ local_commit_seq: number;
27
+ /** Original client_id from the local client */
28
+ client_id: string;
29
+ /** Original client_commit_id from the local client */
30
+ client_commit_id: string;
31
+ /** Operations JSON for forwarding */
32
+ operations_json: string;
33
+ /** Client schema version when commit was created */
34
+ schema_version: number;
35
+ /** Current status of this entry */
36
+ status: RelayForwardOutboxStatus;
37
+ /** Main server's commit_seq after forwarding (null until confirmed) */
38
+ main_commit_seq: number | null;
39
+ /** Error message if status is 'failed' */
40
+ error: string | null;
41
+ /** Last response JSON from main server */
42
+ last_response_json: string | null;
43
+ /** Creation timestamp */
44
+ created_at: Generated<number>;
45
+ /** Last update timestamp */
46
+ updated_at: Generated<number>;
47
+ /** Number of forward attempts */
48
+ attempt_count: Generated<number>;
49
+ }
50
+ /**
51
+ * Sequence map - Maps local to main commit sequences.
52
+ *
53
+ * Tracks the relationship between relay's local commit_seq
54
+ * and the main server's global commit_seq.
55
+ */
56
+ interface RelaySequenceMapTable {
57
+ /** Relay's local commit sequence */
58
+ local_commit_seq: number;
59
+ /** Main server's commit sequence (null if not yet forwarded) */
60
+ main_commit_seq: number | null;
61
+ /** Mapping status */
62
+ status: RelaySequenceMapStatus;
63
+ /** When this mapping was created */
64
+ created_at: Generated<number>;
65
+ /** When this mapping was last updated */
66
+ updated_at: Generated<number>;
67
+ }
68
+ /**
69
+ * Forward conflicts - Conflicts encountered when forwarding to main.
70
+ *
71
+ * When a local commit is rejected by the main server due to conflicts,
72
+ * the details are stored here for application-level handling.
73
+ */
74
+ interface RelayForwardConflictTable {
75
+ /** Unique identifier */
76
+ id: string;
77
+ /** Local commit sequence that caused the conflict */
78
+ local_commit_seq: number;
79
+ /** Original client_id from the local client */
80
+ client_id: string;
81
+ /** Original client_commit_id from the local client */
82
+ client_commit_id: string;
83
+ /** Full rejection response from main server */
84
+ response_json: string;
85
+ /** When the conflict was recorded */
86
+ created_at: number;
87
+ /** When the conflict was resolved (null if unresolved) */
88
+ resolved_at: number | null;
89
+ }
90
+ /**
91
+ * Relay config - Key-value store for relay state.
92
+ *
93
+ * Stores configuration and runtime state like:
94
+ * - scope_keys: subscribed scopes
95
+ * - main_cursor: last pulled commit_seq from main server
96
+ * - mode: online/offline/reconnecting
97
+ */
98
+ interface RelayConfigTable {
99
+ /** Configuration key */
100
+ key: string;
101
+ /** JSON-encoded value */
102
+ value_json: string;
103
+ }
104
+ /**
105
+ * Database interface for relay-specific tables.
106
+ * Merge this with SyncCoreDb for the full database interface.
107
+ */
108
+ export interface RelayDb {
109
+ relay_forward_outbox: RelayForwardOutboxTable;
110
+ relay_sequence_map: RelaySequenceMapTable;
111
+ relay_forward_conflicts: RelayForwardConflictTable;
112
+ relay_config: RelayConfigTable;
113
+ }
114
+ /**
115
+ * Full database interface required by the relay runtime.
116
+ *
117
+ * Includes:
118
+ * - Sync core tables (commit log, cursors, etc.)
119
+ * - Relay-specific tables (outbox, sequence map, config, conflicts)
120
+ */
121
+ export type RelayDatabase = SyncCoreDb & RelayDb;
122
+ /**
123
+ * Forward outbox entry (with parsed operations).
124
+ */
125
+ export interface ForwardOutboxEntry {
126
+ id: string;
127
+ local_commit_seq: number;
128
+ client_id: string;
129
+ client_commit_id: string;
130
+ operations: Array<{
131
+ table: string;
132
+ row_id: string;
133
+ op: 'upsert' | 'delete';
134
+ payload: Record<string, unknown> | null;
135
+ base_version?: number | null;
136
+ }>;
137
+ schema_version: number;
138
+ status: RelayForwardOutboxStatus;
139
+ main_commit_seq: number | null;
140
+ error: string | null;
141
+ created_at: number;
142
+ updated_at: number;
143
+ attempt_count: number;
144
+ }
145
+ /**
146
+ * Forward conflict entry (with parsed response).
147
+ */
148
+ export interface ForwardConflictEntry {
149
+ id: string;
150
+ local_commit_seq: number;
151
+ client_id: string;
152
+ client_commit_id: string;
153
+ response: unknown;
154
+ created_at: number;
155
+ resolved_at: number | null;
156
+ }
157
+ export {};
158
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/schema.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @syncular/relay - Database schema types
3
+ *
4
+ * Relay-specific tables for edge relay servers.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @syncular/relay - Server Role
3
+ *
4
+ * Hono routes for serving local clients.
5
+ */
6
+ import type { ServerSyncDialect, TableRegistry } from '@syncular/server';
7
+ import type { Context } from 'hono';
8
+ import { Hono } from 'hono';
9
+ import type { Kysely } from 'kysely';
10
+ import type { RelayRealtime } from '../realtime';
11
+ import type { RelayDatabase } from '../schema';
12
+ /**
13
+ * Options for creating relay routes.
14
+ */
15
+ export interface CreateRelayRoutesOptions<DB extends RelayDatabase = RelayDatabase> {
16
+ db: Kysely<DB>;
17
+ dialect: ServerSyncDialect;
18
+ shapes: TableRegistry<DB>;
19
+ realtime: RelayRealtime;
20
+ /**
21
+ * Called after a commit is successfully applied locally.
22
+ * Use this to trigger forwarding and notify local clients.
23
+ */
24
+ onCommit?: (localCommitSeq: number, affectedTables: string[]) => Promise<void>;
25
+ /**
26
+ * Optional: authenticate requests. Return actor ID or null for unauthorized.
27
+ * If not provided, all requests are allowed with actor ID 'anonymous'.
28
+ */
29
+ authenticate?: (c: Context) => Promise<{
30
+ actorId: string;
31
+ } | null>;
32
+ /**
33
+ * Max operations per pushed commit (default: 200).
34
+ */
35
+ maxOperationsPerPush?: number;
36
+ /**
37
+ * Max subscriptions per pull request (default: 200).
38
+ */
39
+ maxSubscriptionsPerPull?: number;
40
+ /**
41
+ * Max commits per pull request (default: 100).
42
+ */
43
+ maxPullLimitCommits?: number;
44
+ }
45
+ /**
46
+ * Create Hono routes for relay server-role endpoints.
47
+ *
48
+ * Provides:
49
+ * - POST /pull (commit stream + optional bootstrap snapshots)
50
+ * - POST /push (commit ingestion)
51
+ * - GET /realtime (WebSocket wake-up notifications)
52
+ */
53
+ export declare function createRelayRoutes<DB extends RelayDatabase = RelayDatabase>(options: CreateRelayRoutesOptions<DB>): Hono;
54
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server-role/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAI/C;;GAEG;AACH,MAAM,WAAW,wBAAwB,CACvC,EAAE,SAAS,aAAa,GAAG,aAAa;IAExC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,EAAE,iBAAiB,CAAC;IAC3B,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CACT,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EAAE,KACrB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACnE;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;OAEG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAUD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,aAAa,GAAG,aAAa,EACxE,OAAO,EAAE,wBAAwB,CAAC,EAAE,CAAC,GACpC,IAAI,CAqQN"}