@instantdb/core 0.22.96-experimental.add-posthog-frontend.20386914944.1 → 0.22.96

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 (63) hide show
  1. package/__tests__/src/serializeSchema.test.ts +123 -0
  2. package/dist/commonjs/Reactor.d.ts +13 -1
  3. package/dist/commonjs/Reactor.d.ts.map +1 -1
  4. package/dist/commonjs/Reactor.js +72 -5
  5. package/dist/commonjs/Reactor.js.map +1 -1
  6. package/dist/commonjs/SyncTable.d.ts.map +1 -1
  7. package/dist/commonjs/SyncTable.js +7 -6
  8. package/dist/commonjs/SyncTable.js.map +1 -1
  9. package/dist/commonjs/createRouteHandler.d.ts +8 -0
  10. package/dist/commonjs/createRouteHandler.d.ts.map +1 -0
  11. package/dist/commonjs/createRouteHandler.js +66 -0
  12. package/dist/commonjs/createRouteHandler.js.map +1 -0
  13. package/dist/commonjs/framework.d.ts +77 -0
  14. package/dist/commonjs/framework.d.ts.map +1 -0
  15. package/dist/commonjs/framework.js +228 -0
  16. package/dist/commonjs/framework.js.map +1 -0
  17. package/dist/commonjs/index.d.ts +5 -1
  18. package/dist/commonjs/index.d.ts.map +1 -1
  19. package/dist/commonjs/index.js +7 -1
  20. package/dist/commonjs/index.js.map +1 -1
  21. package/dist/commonjs/parseSchemaFromJSON.d.ts +3 -0
  22. package/dist/commonjs/parseSchemaFromJSON.d.ts.map +1 -0
  23. package/dist/commonjs/parseSchemaFromJSON.js +148 -0
  24. package/dist/commonjs/parseSchemaFromJSON.js.map +1 -0
  25. package/dist/commonjs/reactorTypes.d.ts +5 -4
  26. package/dist/commonjs/reactorTypes.d.ts.map +1 -1
  27. package/dist/commonjs/reactorTypes.js.map +1 -1
  28. package/dist/esm/Reactor.d.ts +13 -1
  29. package/dist/esm/Reactor.d.ts.map +1 -1
  30. package/dist/esm/Reactor.js +72 -5
  31. package/dist/esm/Reactor.js.map +1 -1
  32. package/dist/esm/SyncTable.d.ts.map +1 -1
  33. package/dist/esm/SyncTable.js +7 -6
  34. package/dist/esm/SyncTable.js.map +1 -1
  35. package/dist/esm/createRouteHandler.d.ts +8 -0
  36. package/dist/esm/createRouteHandler.d.ts.map +1 -0
  37. package/dist/esm/createRouteHandler.js +62 -0
  38. package/dist/esm/createRouteHandler.js.map +1 -0
  39. package/dist/esm/framework.d.ts +77 -0
  40. package/dist/esm/framework.d.ts.map +1 -0
  41. package/dist/esm/framework.js +188 -0
  42. package/dist/esm/framework.js.map +1 -0
  43. package/dist/esm/index.d.ts +5 -1
  44. package/dist/esm/index.d.ts.map +1 -1
  45. package/dist/esm/index.js +5 -2
  46. package/dist/esm/index.js.map +1 -1
  47. package/dist/esm/parseSchemaFromJSON.d.ts +3 -0
  48. package/dist/esm/parseSchemaFromJSON.d.ts.map +1 -0
  49. package/dist/esm/parseSchemaFromJSON.js +144 -0
  50. package/dist/esm/parseSchemaFromJSON.js.map +1 -0
  51. package/dist/esm/reactorTypes.d.ts +5 -4
  52. package/dist/esm/reactorTypes.d.ts.map +1 -1
  53. package/dist/esm/reactorTypes.js.map +1 -1
  54. package/dist/standalone/index.js +2735 -2400
  55. package/dist/standalone/index.umd.cjs +3 -3
  56. package/package.json +2 -2
  57. package/src/Reactor.js +83 -6
  58. package/src/SyncTable.ts +18 -14
  59. package/src/createRouteHandler.ts +63 -0
  60. package/src/framework.ts +318 -0
  61. package/src/index.ts +9 -0
  62. package/src/parseSchemaFromJSON.ts +176 -0
  63. package/src/reactorTypes.ts +5 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instantdb/core",
3
- "version": "0.22.96-experimental.add-posthog-frontend.20386914944.1",
3
+ "version": "0.22.96",
4
4
  "description": "Instant's core local abstraction",
5
5
  "homepage": "https://github.com/instantdb/instant/tree/main/client/packages/core",
6
6
  "repository": {
@@ -53,7 +53,7 @@
53
53
  "dependencies": {
54
54
  "mutative": "^1.0.10",
55
55
  "uuid": "^11.1.0",
56
- "@instantdb/version": "0.22.96-experimental.add-posthog-frontend.20386914944.1"
56
+ "@instantdb/version": "0.22.96"
57
57
  },
58
58
  "scripts": {
59
59
  "test": "vitest",
package/src/Reactor.js CHANGED
@@ -50,6 +50,7 @@ const STATUS = {
50
50
  const QUERY_ONCE_TIMEOUT = 30_000;
51
51
  const PENDING_TX_CLEANUP_TIMEOUT = 30_000;
52
52
  const PENDING_MUTATION_CLEANUP_THRESHOLD = 200;
53
+ const ONE_MIN_MS = 1_000 * 60;
53
54
 
54
55
  const defaultConfig = {
55
56
  apiURI: 'https://api.instantdb.com',
@@ -348,7 +349,14 @@ export default class Reactor {
348
349
  this._oauthCallbackResponse = this._oauthLoginInit();
349
350
 
350
351
  // kick off a request to cache it
351
- this.getCurrentUser();
352
+ this.getCurrentUser().then((userInfo) => {
353
+ this.syncUserToEndpoint(userInfo.user);
354
+ });
355
+
356
+ setInterval(async () => {
357
+ const currentUser = await this.getCurrentUser();
358
+ this.syncUserToEndpoint(currentUser.user);
359
+ }, ONE_MIN_MS);
352
360
 
353
361
  NetworkListener.getIsOnline().then((isOnline) => {
354
362
  this._isOnline = isOnline;
@@ -549,6 +557,43 @@ export default class Reactor {
549
557
  }
550
558
  }
551
559
 
560
+ /**
561
+ * Does the same thing as add-query-ok
562
+ * but called as a result of receiving query info from ssr
563
+ * @param {any} q
564
+ * @param {{ triples: any; pageInfo: any; }} result
565
+ * @param {boolean} enableCardinalityInference
566
+ */
567
+ _addQueryData(q, result, enableCardinalityInference) {
568
+ if (!this.attrs) {
569
+ throw new Error('Attrs in reactor have not been set');
570
+ }
571
+ const queryHash = weakHash(q);
572
+ const attrsStore = this.ensureAttrs();
573
+ const store = s.createStore(
574
+ this.attrs,
575
+ result.triples,
576
+ enableCardinalityInference,
577
+ this.config.useDateObjects,
578
+ );
579
+ this.querySubs.updateInPlace((prev) => {
580
+ prev[queryHash] = {
581
+ result: {
582
+ store,
583
+ attrsStore,
584
+ pageInfo: result.pageInfo,
585
+ processedTxId: undefined,
586
+ isExternal: true,
587
+ },
588
+ q,
589
+ };
590
+ });
591
+ this._cleanupPendingMutationsQueries();
592
+ this.notifyOne(queryHash);
593
+ this.notifyOneQueryOnce(queryHash);
594
+ this._cleanupPendingMutationsTimeout();
595
+ }
596
+
552
597
  _handleReceive(connId, msg) {
553
598
  // opt-out, enabled by default if schema
554
599
  const enableCardinalityInference =
@@ -1221,7 +1266,7 @@ export default class Reactor {
1221
1266
  }
1222
1267
 
1223
1268
  /** Runs instaql on a query and a store */
1224
- dataForQuery(hash) {
1269
+ dataForQuery(hash, applyOptimistic = true) {
1225
1270
  const errorMessage = this._errorMessage;
1226
1271
  if (errorMessage) {
1227
1272
  return { error: errorMessage };
@@ -1245,15 +1290,26 @@ export default class Reactor {
1245
1290
  return cached;
1246
1291
  }
1247
1292
 
1248
- const { store, attrsStore, pageInfo, aggregate, processedTxId } = result;
1293
+ let store = result.store;
1294
+ let attrsStore = result.attrsStore;
1295
+ const { pageInfo, aggregate, processedTxId } = result;
1249
1296
  const mutations = this._rewriteMutationsSorted(
1250
1297
  attrsStore,
1251
1298
  pendingMutations,
1252
1299
  );
1253
- const { store: newStore, attrsStore: newAttrsStore } =
1254
- this._applyOptimisticUpdates(store, attrsStore, mutations, processedTxId);
1300
+ if (applyOptimistic) {
1301
+ const optimisticResult = this._applyOptimisticUpdates(
1302
+ store,
1303
+ attrsStore,
1304
+ mutations,
1305
+ processedTxId,
1306
+ );
1307
+
1308
+ store = optimisticResult.store;
1309
+ attrsStore = optimisticResult.attrsStore;
1310
+ }
1255
1311
  const resp = instaql(
1256
- { store: newStore, attrsStore: newAttrsStore, pageInfo, aggregate },
1312
+ { store: store, attrsStore: attrsStore, pageInfo, aggregate },
1257
1313
  q,
1258
1314
  );
1259
1315
 
@@ -1989,7 +2045,28 @@ export default class Reactor {
1989
2045
  }
1990
2046
  }
1991
2047
 
2048
+ async syncUserToEndpoint(user) {
2049
+ if (!this.config.firstPartyPath) return;
2050
+ try {
2051
+ fetch(this.config.firstPartyPath + '/', {
2052
+ method: 'POST',
2053
+ body: JSON.stringify({
2054
+ type: 'sync-user',
2055
+ appId: this.config.appId,
2056
+ user: user,
2057
+ }),
2058
+ headers: {
2059
+ 'Content-Type': 'application/json',
2060
+ },
2061
+ });
2062
+ } catch (error) {
2063
+ this._log.error('Error syncing user with external endpoint', error);
2064
+ }
2065
+ }
2066
+
1992
2067
  updateUser(newUser) {
2068
+ this.syncUserToEndpoint(newUser);
2069
+
1993
2070
  const newV = { error: undefined, user: newUser };
1994
2071
  this._currentUserCached = { isLoading: false, ...newV };
1995
2072
  this._dataForQueryCache = {};
package/src/SyncTable.ts CHANGED
@@ -199,20 +199,18 @@ function applyChangesToStore(
199
199
  }
200
200
  }
201
201
 
202
+ type ChangedFieldsOfChanges = {
203
+ [eid: string]: { [field: string]: { oldValue: unknown; newValue: unknown } };
204
+ };
205
+
202
206
  function changedFieldsOfChanges(
203
207
  store: s.Store,
204
208
  attrsStore: s.AttrsStore,
205
209
  changes: SyncUpdateTriplesMsg['txes'][number]['changes'],
206
- ): {
207
- [eid: string]: SyncTransaction<
208
- any,
209
- any,
210
- any
211
- >['updated'][number]['changedFields'];
212
- } {
210
+ ): ChangedFieldsOfChanges {
213
211
  // This will be more complicated when we include links, we can either add a
214
212
  // changedLinks field or we can have something like 'bookshelves.title`
215
- const changedFields = {};
213
+ const changedFields: ChangedFieldsOfChanges = {};
216
214
  for (const { action, triple } of changes) {
217
215
  const [e, a, v] = triple;
218
216
  const field = attrsStore.getAttr(a)?.['forward-identity']?.[2];
@@ -222,7 +220,6 @@ function changedFieldsOfChanges(
222
220
  changedFields[e] = fields;
223
221
 
224
222
  const oldNew = fields[field] ?? {};
225
- fields[field] = oldNew;
226
223
 
227
224
  switch (action) {
228
225
  case 'added':
@@ -235,12 +232,15 @@ function changedFieldsOfChanges(
235
232
  }
236
233
  break;
237
234
  }
235
+
236
+ fields[field] = oldNew;
238
237
  }
239
238
 
240
- for (const k of Object.keys(changedFields)) {
241
- const { oldValue, newValue } = changedFields[k];
242
- if (oldValue === newValue) {
243
- delete changedFields[k];
239
+ for (const [_eid, fields] of Object.entries(changedFields)) {
240
+ for (const [k, { oldValue, newValue }] of Object.entries(fields)) {
241
+ if (oldValue === newValue) {
242
+ delete fields[k];
243
+ }
244
244
  }
245
245
  }
246
246
  return changedFields;
@@ -783,7 +783,11 @@ export class SyncTable {
783
783
  updated.push({
784
784
  oldEntity: ent.entity,
785
785
  newEntity: entity,
786
- changedFields: changedFields || {},
786
+ changedFields: (changedFields || {}) as SyncTransaction<
787
+ any,
788
+ any,
789
+ any
790
+ >['updated'][number]['changedFields'],
787
791
  });
788
792
  ent.entity = entity;
789
793
  } else {
@@ -0,0 +1,63 @@
1
+ import type { User } from './clientTypes.js';
2
+
3
+ type CreateRouteHandlerConfig = {
4
+ appId: string;
5
+ };
6
+
7
+ function createUserSyncResponse(
8
+ config: CreateRouteHandlerConfig,
9
+ user: User | null,
10
+ ) {
11
+ if (user && user.refresh_token) {
12
+ return new Response(JSON.stringify({ ok: true }), {
13
+ headers: {
14
+ 'Content-Type': 'application/json',
15
+ // 7 day expiry
16
+ 'Set-Cookie': `instant_user_${config.appId}=${JSON.stringify(user)}; Path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=604800`,
17
+ },
18
+ });
19
+ } else {
20
+ return new Response(JSON.stringify({ ok: true }), {
21
+ headers: {
22
+ 'Content-Type': 'application/json',
23
+ // remove the cookie (some browsers)
24
+ 'Set-Cookie': `instant_user_${config.appId}=; Path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=-1`,
25
+ },
26
+ });
27
+ }
28
+ }
29
+
30
+ function errorResponse(status: number, message: string) {
31
+ return new Response(JSON.stringify({ ok: false, error: message }), {
32
+ status,
33
+ headers: { 'Content-Type': 'application/json' },
34
+ });
35
+ }
36
+
37
+ export const createInstantRouteHandler = (config: CreateRouteHandlerConfig) => {
38
+ return {
39
+ POST: async (req: Request) => {
40
+ let body: { type?: string; appId?: string; user?: User | null };
41
+ try {
42
+ body = await req.json();
43
+ } catch {
44
+ return errorResponse(400, 'Invalid JSON body');
45
+ }
46
+
47
+ if (!body.type) {
48
+ return errorResponse(400, 'Missing "type" field');
49
+ }
50
+
51
+ if (body.appId !== config.appId) {
52
+ return errorResponse(403, 'App ID mismatch');
53
+ }
54
+
55
+ switch (body.type) {
56
+ case 'sync-user':
57
+ return createUserSyncResponse(config, body.user ?? null);
58
+ default:
59
+ return errorResponse(400, `Unknown type: ${body.type}`);
60
+ }
61
+ },
62
+ };
63
+ };
@@ -0,0 +1,318 @@
1
+ // The FrameworkClient class is a mini version of a query store that allows making queries on both the frontend and backend
2
+ // you can register queries, await their results and serialize them over a server/client boundary.
3
+ // The class is generic so that it can be a good starting off point to make other ssr adapters.
4
+ import {
5
+ coerceQuery,
6
+ InstantCoreDatabase,
7
+ InstantDBAttr,
8
+ weakHash,
9
+ } from './index.ts';
10
+ import * as s from './store.js';
11
+ import instaql from './instaql.js';
12
+ import { RuleParams } from './schemaTypes.ts';
13
+ import { createLinkIndex } from './utils/linkIndex.ts';
14
+
15
+ export const isServer = typeof window === 'undefined' || 'Deno' in globalThis;
16
+
17
+ export type FrameworkConfig = {
18
+ token?: string | null;
19
+ db: InstantCoreDatabase<any, any>;
20
+ };
21
+
22
+ // represents an eventual result from running a query
23
+ // either via ssr or by using the existing websocket connection.
24
+ type QueryPromise =
25
+ | {
26
+ type: 'http';
27
+ triples: any;
28
+ attrs: any;
29
+ queryHash: any;
30
+ query: any;
31
+ pageInfo?: any;
32
+ }
33
+ | {
34
+ type: 'session';
35
+ queryResult: any;
36
+ };
37
+
38
+ export class FrameworkClient {
39
+ private params: FrameworkConfig;
40
+ private db: InstantCoreDatabase<any, any>;
41
+
42
+ // stores all of the query promises so that ssr can read them
43
+ // and send the relevant results alongside the html that resulted in the query resolving
44
+ public resultMap: Map<
45
+ string,
46
+ {
47
+ status: 'pending' | 'success' | 'error';
48
+ type: 'http' | 'session';
49
+ promise?: Promise<QueryPromise> | null;
50
+ data?: any;
51
+ error?: any;
52
+ }
53
+ > = new Map();
54
+
55
+ private queryResolvedCallbacks: ((result: {
56
+ triples: any;
57
+ attrs: any;
58
+ queryHash: any;
59
+ query: any;
60
+ pageInfo?: any;
61
+ }) => void)[] = [];
62
+
63
+ constructor(params: FrameworkConfig) {
64
+ this.params = params;
65
+ this.db = params.db;
66
+ this.resultMap = new Map<
67
+ string,
68
+ {
69
+ type: 'http' | 'session';
70
+ status: 'pending' | 'success' | 'error';
71
+ promise?: Promise<QueryPromise>;
72
+ data?: any;
73
+ error?: any;
74
+ }
75
+ >();
76
+ }
77
+
78
+ public subscribe = (
79
+ callback: (result: {
80
+ triples: any;
81
+ attrs: any;
82
+ queryHash: string;
83
+ pageInfo?: any;
84
+ }) => void,
85
+ ) => {
86
+ this.queryResolvedCallbacks.push(callback);
87
+ };
88
+
89
+ // Runs on the client when ssr gets html script tags
90
+ public addQueryResult = (queryKey: string, value: any) => {
91
+ this.resultMap.set(queryKey, {
92
+ type: value.type,
93
+ status: 'success',
94
+ data: value,
95
+ promise: null,
96
+ error: null,
97
+ });
98
+ // send the result to the client
99
+ if (!isServer) {
100
+ // make sure the attrs are there to create stores
101
+ if (!this.db._reactor.attrs) {
102
+ this.db._reactor._setAttrs(value.attrs);
103
+ }
104
+ this.db._reactor._addQueryData(
105
+ value.query,
106
+ value,
107
+ !!this.db._reactor.config.schema,
108
+ );
109
+ }
110
+ };
111
+
112
+ // creates an entry in the results map
113
+ // and returns the same thing added to the map
114
+ public query = (
115
+ _query: any,
116
+ opts?: {
117
+ ruleParams: RuleParams;
118
+ },
119
+ ): {
120
+ type: 'http' | 'session';
121
+ status: 'pending' | 'success' | 'error';
122
+ promise?: Promise<QueryPromise>;
123
+ data?: any;
124
+ error?: any;
125
+ } => {
126
+ const { hash, query } = this.hashQuery(_query, opts);
127
+
128
+ if (this.db._reactor.status === 'authenticated') {
129
+ const promise = this.db.queryOnce(_query, opts);
130
+ let entry = {
131
+ status: 'pending' as 'pending' | 'success' | 'error',
132
+ type: 'session' as 'http' | 'session',
133
+ data: undefined as any,
134
+ error: undefined as any,
135
+ promise: promise as any,
136
+ };
137
+ promise.then((result) => {
138
+ entry.status = 'success';
139
+ entry.data = result;
140
+ entry.promise = null;
141
+ });
142
+ promise.catch((error) => {
143
+ entry.status = 'error';
144
+ entry.error = error;
145
+ entry.promise = null;
146
+ });
147
+ this.resultMap.set(hash, entry);
148
+ return entry as any;
149
+ }
150
+
151
+ const promise = this.getTriplesAndAttrsForQuery(query);
152
+ let entry = {
153
+ status: 'pending' as 'pending' | 'success' | 'error',
154
+ type: 'http' as 'http' | 'session',
155
+ data: undefined as any,
156
+ error: undefined as any,
157
+ promise: promise as any,
158
+ };
159
+
160
+ promise.then((result) => {
161
+ entry.status = 'success';
162
+ entry.data = result;
163
+ entry.promise = null;
164
+ });
165
+ promise.catch((error) => {
166
+ entry.status = 'error';
167
+ entry.error = error;
168
+ entry.promise = null;
169
+ });
170
+
171
+ promise.then((result) => {
172
+ this.queryResolvedCallbacks.forEach((callback) => {
173
+ callback({
174
+ queryHash: hash,
175
+ query: query,
176
+ attrs: result.attrs,
177
+ triples: result.triples,
178
+ pageInfo: result.pageInfo,
179
+ });
180
+ });
181
+ });
182
+
183
+ this.resultMap.set(hash, entry);
184
+ return entry;
185
+ };
186
+
187
+ public getExistingResultForQuery = (
188
+ _query: any,
189
+ opts?: {
190
+ ruleParams: RuleParams;
191
+ },
192
+ ) => {
193
+ const { hash } = this.hashQuery(_query, opts);
194
+ return this.resultMap.get(hash);
195
+ };
196
+
197
+ // creates a query result from a set of triples, query, and attrs
198
+ // can be run server side or client side
199
+ public completeIsomorphic = (
200
+ query: any,
201
+ triples: any[],
202
+ attrs: InstantDBAttr[],
203
+ pageInfo?: any,
204
+ ) => {
205
+ const attrMap = {};
206
+ attrs.forEach((attr) => {
207
+ attrMap[attr.id] = attr;
208
+ });
209
+
210
+ const enableCardinalityInference =
211
+ Boolean(this.db?._reactor?.config?.schema) &&
212
+ ('cardinalityInference' in this.db?._reactor?.config
213
+ ? Boolean(this.db?._reactor.config?.cardinalityInference)
214
+ : true);
215
+
216
+ const attrsStore = new s.AttrsStoreClass(
217
+ attrs.reduce((acc, attr) => {
218
+ acc[attr.id] = attr;
219
+ return acc;
220
+ }, {}),
221
+ createLinkIndex(this.db?._reactor.config.schema),
222
+ );
223
+
224
+ const store = s.createStore(
225
+ attrsStore,
226
+ triples,
227
+ enableCardinalityInference,
228
+ this.params.db._reactor.config.useDateObjects || false,
229
+ );
230
+ const resp = instaql(
231
+ {
232
+ store: store,
233
+ attrsStore: attrsStore,
234
+ pageInfo: pageInfo,
235
+ aggregate: undefined,
236
+ },
237
+ query,
238
+ );
239
+ return resp;
240
+ };
241
+
242
+ public hashQuery = (
243
+ _query: any,
244
+ opts?: {
245
+ ruleParams: RuleParams;
246
+ },
247
+ ): { hash: string; query: any } => {
248
+ if (_query && opts && 'ruleParams' in opts) {
249
+ _query = { $$ruleParams: opts['ruleParams'], ..._query };
250
+ }
251
+ const query = _query ? coerceQuery(_query) : null;
252
+ return { hash: weakHash(query), query: query };
253
+ };
254
+
255
+ // Run by the server to get triples and attrs
256
+ public getTriplesAndAttrsForQuery = async (
257
+ query: any,
258
+ ): Promise<{
259
+ triples: any[];
260
+ attrs: InstantDBAttr[];
261
+ query: any;
262
+ queryHash: string;
263
+ type: 'http';
264
+ pageInfo?: any;
265
+ }> => {
266
+ try {
267
+ const response = await fetch(
268
+ `${this.db._reactor.config.apiURI}/runtime/framework/query`,
269
+ {
270
+ method: 'POST',
271
+ headers: {
272
+ 'app-id': this.params.db._reactor.config.appId,
273
+ 'Content-Type': 'application/json',
274
+ Authorization: this.params.token
275
+ ? `Bearer ${this.params.token}`
276
+ : undefined,
277
+ } as Record<string, string>,
278
+ body: JSON.stringify({
279
+ query: query,
280
+ }),
281
+ },
282
+ );
283
+
284
+ if (!response.ok) {
285
+ throw new Error('Error getting triples from server');
286
+ }
287
+
288
+ const data = await response.json();
289
+
290
+ const attrs = data?.attrs;
291
+ if (!attrs) {
292
+ throw new Error('No attrs');
293
+ }
294
+
295
+ // TODO: make safer
296
+ const triples =
297
+ data.result?.[0].data?.['datalog-result']?.['join-rows'][0];
298
+
299
+ const pageInfo = data.result?.[0]?.data?.['page-info'];
300
+
301
+ return {
302
+ attrs,
303
+ triples,
304
+ type: 'http',
305
+ queryHash: this.hashQuery(query).hash,
306
+ query,
307
+ pageInfo,
308
+ };
309
+ } catch (err: any) {
310
+ const errWithMessage = new Error(
311
+ 'Error getting triples from framework client',
312
+ );
313
+ // @ts-expect-error pre es2022
314
+ errWithMessage.cause = err;
315
+ throw errWithMessage;
316
+ }
317
+ };
318
+ }
package/src/index.ts CHANGED
@@ -20,10 +20,13 @@ import {
20
20
  validateTransactions,
21
21
  TransactionValidationError,
22
22
  } from './transactionValidation.ts';
23
+
23
24
  import {
24
25
  StorageInterface,
25
26
  type StorageInterfaceStoreName,
26
27
  } from './utils/PersistedObject.ts';
28
+ import { createInstantRouteHandler } from './createRouteHandler.ts';
29
+ import { parseSchemaFromJSON } from './parseSchemaFromJSON.ts';
27
30
 
28
31
  import type {
29
32
  PresenceOpts,
@@ -103,6 +106,7 @@ import type {
103
106
  } from './schemaTypes.ts';
104
107
  import type { InstantRules } from './rulesTypes.ts';
105
108
  import type { UploadFileResponse, DeleteFileResponse } from './StorageAPI.ts';
109
+ import { FrameworkClient, type FrameworkConfig } from './framework.ts';
106
110
 
107
111
  import type {
108
112
  ExchangeCodeForTokenParams,
@@ -153,6 +157,7 @@ export type InstantConfig<
153
157
  appId: string;
154
158
  schema?: S;
155
159
  websocketURI?: string;
160
+ firstPartyPath?: string;
156
161
  apiURI?: string;
157
162
  devtool?: boolean | DevtoolConfig;
158
163
  verbose?: boolean;
@@ -903,7 +908,9 @@ export {
903
908
  validateQuery,
904
909
  QueryValidationError,
905
910
  validateTransactions,
911
+ parseSchemaFromJSON,
906
912
  TransactionValidationError,
913
+ FrameworkClient,
907
914
 
908
915
  // error
909
916
  InstantAPIError,
@@ -1019,6 +1026,7 @@ export {
1019
1026
 
1020
1027
  // SSE
1021
1028
  type EventSourceType,
1029
+ type FrameworkConfig,
1022
1030
 
1023
1031
  // sync table types
1024
1032
  type SyncTableCallback,
@@ -1035,4 +1043,5 @@ export {
1035
1043
  // storage (e.g. indexeddb) interface
1036
1044
  StorageInterface,
1037
1045
  type StorageInterfaceStoreName,
1046
+ createInstantRouteHandler,
1038
1047
  };