@instantdb/admin 0.22.98 → 0.22.99-experimental.add-user-perm-rules.20792844601.1

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/esm/index.js CHANGED
@@ -1,3 +1,12 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { tx, lookup, getOps, i, id, txInit, version as coreVersion, InstantAPIError, validateQuery, validateTransactions, createInstantRouteHandler, } from '@instantdb/core';
2
11
  import version from "./version.js";
3
12
  import { subscribe, } from "./subscribe.js";
@@ -5,14 +14,14 @@ function configWithDefaults(config) {
5
14
  const defaultConfig = {
6
15
  apiURI: 'https://api.instantdb.com',
7
16
  };
8
- const r = { ...defaultConfig, ...config };
17
+ const r = Object.assign(Object.assign({}, defaultConfig), config);
9
18
  return r;
10
19
  }
11
20
  function instantConfigWithDefaults(config) {
12
21
  const defaultConfig = {
13
22
  apiURI: 'https://api.instantdb.com',
14
23
  };
15
- const r = { ...defaultConfig, ...config };
24
+ const r = Object.assign(Object.assign({}, defaultConfig), config);
16
25
  return r;
17
26
  }
18
27
  function withImpersonation(headers, opts) {
@@ -75,32 +84,32 @@ function isNextJSVersionThatCachesFetchByDefault() {
75
84
  function getDefaultFetchOpts() {
76
85
  return isNextJSVersionThatCachesFetchByDefault() ? { cache: 'no-store' } : {};
77
86
  }
78
- async function jsonReject(rejectFn, res) {
79
- const body = await res.text();
80
- try {
81
- const json = JSON.parse(body);
82
- return rejectFn(new InstantAPIError({ status: res.status, body: json }));
83
- }
84
- catch (_e) {
85
- return rejectFn(new InstantAPIError({
86
- status: res.status,
87
- body: { type: undefined, message: body },
88
- }));
89
- }
87
+ function jsonReject(rejectFn, res) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ const body = yield res.text();
90
+ try {
91
+ const json = JSON.parse(body);
92
+ return rejectFn(new InstantAPIError({ status: res.status, body: json }));
93
+ }
94
+ catch (_e) {
95
+ return rejectFn(new InstantAPIError({
96
+ status: res.status,
97
+ body: { type: undefined, message: body },
98
+ }));
99
+ }
100
+ });
90
101
  }
91
- async function jsonFetch(input, init) {
92
- const defaultFetchOpts = getDefaultFetchOpts();
93
- const headers = {
94
- ...(init?.headers || {}),
95
- 'Instant-Admin-Version': version,
96
- 'Instant-Core-Version': coreVersion,
97
- };
98
- const res = await fetch(input, { ...defaultFetchOpts, ...init, headers });
99
- if (res.status === 200) {
100
- const json = await res.json();
101
- return Promise.resolve(json);
102
- }
103
- return jsonReject((x) => Promise.reject(x), res);
102
+ function jsonFetch(input, init) {
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ const defaultFetchOpts = getDefaultFetchOpts();
105
+ const headers = Object.assign(Object.assign({}, ((init === null || init === void 0 ? void 0 : init.headers) || {})), { 'Instant-Admin-Version': version, 'Instant-Core-Version': coreVersion });
106
+ const res = yield fetch(input, Object.assign(Object.assign(Object.assign({}, defaultFetchOpts), init), { headers }));
107
+ if (res.status === 200) {
108
+ const json = yield res.json();
109
+ return Promise.resolve(json);
110
+ }
111
+ return jsonReject((x) => Promise.reject(x), res);
112
+ });
104
113
  }
105
114
  /**
106
115
  *
@@ -132,12 +141,8 @@ function init(
132
141
  // Allows config with missing `useDateObjects`, but keeps `UseDates`
133
142
  // as a non-nullable in the InstantConfig type.
134
143
  config) {
135
- const configStrict = {
136
- ...config,
137
- appId: config.appId?.trim(),
138
- adminToken: config.adminToken?.trim(),
139
- useDateObjects: (config.useDateObjects ?? false),
140
- };
144
+ var _a, _b, _c;
145
+ const configStrict = Object.assign(Object.assign({}, config), { appId: (_a = config.appId) === null || _a === void 0 ? void 0 : _a.trim(), adminToken: (_b = config.adminToken) === null || _b === void 0 ? void 0 : _b.trim(), useDateObjects: ((_c = config.useDateObjects) !== null && _c !== void 0 ? _c : false) });
141
146
  return new InstantAdminDatabase(configStrict);
142
147
  }
143
148
  /**
@@ -160,171 +165,175 @@ function steps(inputChunks) {
160
165
  return chunks.flatMap(getOps);
161
166
  }
162
167
  class Rooms {
163
- config;
164
168
  constructor(config) {
165
169
  this.config = config;
166
170
  }
167
- async getPresence(roomType, roomId) {
168
- const res = await jsonFetch(`${this.config.apiURI}/admin/rooms/presence?room-type=${String(roomType)}&room-id=${roomId}`, {
169
- method: 'GET',
170
- headers: authorizedHeaders(this.config),
171
+ getPresence(roomType, roomId) {
172
+ return __awaiter(this, void 0, void 0, function* () {
173
+ const res = yield jsonFetch(`${this.config.apiURI}/admin/rooms/presence?room-type=${String(roomType)}&room-id=${roomId}`, {
174
+ method: 'GET',
175
+ headers: authorizedHeaders(this.config),
176
+ });
177
+ return res.sessions || {};
171
178
  });
172
- return res.sessions || {};
173
179
  }
174
180
  }
175
181
  class Auth {
176
- config;
177
182
  constructor(config) {
178
- this.config = config;
179
- this.createToken = this.createToken.bind(this);
180
- }
181
- /**
182
- * Generates a magic code for the user with the given email.
183
- * This is useful if you want to use your own email provider
184
- * to send magic codes.
185
- *
186
- * @example
187
- * // Generate a magic code
188
- * const { code } = await db.auth.generateMagicCode({ email })
189
- * // Send the magic code to the user with your own email provider
190
- * await customEmailProvider.sendMagicCode(email, code)
191
- *
192
- * @see https://instantdb.com/docs/backend#custom-magic-codes
193
- */
194
- generateMagicCode = async (email) => {
195
- return jsonFetch(`${this.config.apiURI}/admin/magic_code`, {
196
- method: 'POST',
197
- headers: authorizedHeaders(this.config),
198
- body: JSON.stringify({ email }),
183
+ /**
184
+ * Generates a magic code for the user with the given email.
185
+ * This is useful if you want to use your own email provider
186
+ * to send magic codes.
187
+ *
188
+ * @example
189
+ * // Generate a magic code
190
+ * const { code } = await db.auth.generateMagicCode({ email })
191
+ * // Send the magic code to the user with your own email provider
192
+ * await customEmailProvider.sendMagicCode(email, code)
193
+ *
194
+ * @see https://instantdb.com/docs/backend#custom-magic-codes
195
+ */
196
+ this.generateMagicCode = (email) => __awaiter(this, void 0, void 0, function* () {
197
+ return jsonFetch(`${this.config.apiURI}/admin/magic_code`, {
198
+ method: 'POST',
199
+ headers: authorizedHeaders(this.config),
200
+ body: JSON.stringify({ email }),
201
+ });
199
202
  });
200
- };
201
- /**
202
- * Sends a magic code to the user with the given email.
203
- * This uses Instant's built-in email provider.
204
- *
205
- * @example
206
- * // Send an email to user with magic code
207
- * await db.auth.sendMagicCode({ email })
208
- *
209
- * @see https://instantdb.com/docs/backend#custom-magic-codes
210
- */
211
- sendMagicCode = async (email) => {
212
- return jsonFetch(`${this.config.apiURI}/admin/send_magic_code`, {
213
- method: 'POST',
214
- headers: authorizedHeaders(this.config),
215
- body: JSON.stringify({ email }),
203
+ /**
204
+ * Sends a magic code to the user with the given email.
205
+ * This uses Instant's built-in email provider.
206
+ *
207
+ * @example
208
+ * // Send an email to user with magic code
209
+ * await db.auth.sendMagicCode({ email })
210
+ *
211
+ * @see https://instantdb.com/docs/backend#custom-magic-codes
212
+ */
213
+ this.sendMagicCode = (email) => __awaiter(this, void 0, void 0, function* () {
214
+ return jsonFetch(`${this.config.apiURI}/admin/send_magic_code`, {
215
+ method: 'POST',
216
+ headers: authorizedHeaders(this.config),
217
+ body: JSON.stringify({ email }),
218
+ });
216
219
  });
217
- };
218
- /**
219
- * Verifies a magic code for the user with the given email.
220
- *
221
- * @example
222
- * const user = await db.auth.verifyMagicCode({ email, code })
223
- * console.log("Verified user:", user)
224
- *
225
- * @see https://instantdb.com/docs/backend#custom-magic-codes
226
- */
227
- verifyMagicCode = async (email, code) => {
228
- const { user } = await jsonFetch(`${this.config.apiURI}/admin/verify_magic_code`, {
229
- method: 'POST',
230
- headers: authorizedHeaders(this.config),
231
- body: JSON.stringify({ email, code }),
220
+ /**
221
+ * Verifies a magic code for the user with the given email.
222
+ *
223
+ * @example
224
+ * const user = await db.auth.verifyMagicCode({ email, code })
225
+ * console.log("Verified user:", user)
226
+ *
227
+ * @see https://instantdb.com/docs/backend#custom-magic-codes
228
+ */
229
+ this.verifyMagicCode = (email, code) => __awaiter(this, void 0, void 0, function* () {
230
+ const { user } = yield jsonFetch(`${this.config.apiURI}/admin/verify_magic_code`, {
231
+ method: 'POST',
232
+ headers: authorizedHeaders(this.config),
233
+ body: JSON.stringify({ email, code }),
234
+ });
235
+ return user;
232
236
  });
233
- return user;
234
- };
235
- async createToken(input) {
236
- const body = typeof input === 'string' ? { email: input } : input;
237
- const ret = await jsonFetch(`${this.config.apiURI}/admin/refresh_tokens`, {
238
- method: 'POST',
239
- headers: authorizedHeaders(this.config),
240
- body: JSON.stringify(body),
237
+ /**
238
+ * Verifies a given token and returns the associated user.
239
+ *
240
+ * This is often useful for writing custom endpoints, where you need
241
+ * to authenticate users.
242
+ *
243
+ * @example
244
+ * app.post('/custom_endpoint', async (req, res) => {
245
+ * const user = await db.auth.verifyToken(req.headers['token'])
246
+ * if (!user) {
247
+ * return res.status(401).send('Uh oh, you are not authenticated')
248
+ * }
249
+ * // ...
250
+ * })
251
+ * @see https://instantdb.com/docs/backend#custom-endpoints
252
+ */
253
+ this.verifyToken = (token) => __awaiter(this, void 0, void 0, function* () {
254
+ const res = yield jsonFetch(`${this.config.apiURI}/runtime/auth/verify_refresh_token`, {
255
+ method: 'POST',
256
+ headers: { 'content-type': 'application/json' },
257
+ body: JSON.stringify({
258
+ 'app-id': this.config.appId,
259
+ 'refresh-token': token,
260
+ }),
261
+ });
262
+ return res.user;
241
263
  });
242
- return ret.user.refresh_token;
243
- }
244
- /**
245
- * Verifies a given token and returns the associated user.
246
- *
247
- * This is often useful for writing custom endpoints, where you need
248
- * to authenticate users.
249
- *
250
- * @example
251
- * app.post('/custom_endpoint', async (req, res) => {
252
- * const user = await db.auth.verifyToken(req.headers['token'])
253
- * if (!user) {
254
- * return res.status(401).send('Uh oh, you are not authenticated')
255
- * }
256
- * // ...
257
- * })
258
- * @see https://instantdb.com/docs/backend#custom-endpoints
259
- */
260
- verifyToken = async (token) => {
261
- const res = await jsonFetch(`${this.config.apiURI}/runtime/auth/verify_refresh_token`, {
262
- method: 'POST',
263
- headers: { 'content-type': 'application/json' },
264
- body: JSON.stringify({
265
- 'app-id': this.config.appId,
266
- 'refresh-token': token,
267
- }),
264
+ /**
265
+ * Retrieves an app user by id, email, or refresh token.
266
+ *
267
+ * @example
268
+ * try {
269
+ * const user = await db.auth.getUser({ email })
270
+ * console.log("Found user:", user)
271
+ * } catch (err) {
272
+ * console.error("Failed to retrieve user:", err.message);
273
+ * }
274
+ *
275
+ * @see https://instantdb.com/docs/backend#retrieve-a-user
276
+ */
277
+ this.getUser = (params) => __awaiter(this, void 0, void 0, function* () {
278
+ const qs = Object.entries(params)
279
+ .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
280
+ .join('&');
281
+ const response = yield jsonFetch(`${this.config.apiURI}/admin/users?${qs}`, {
282
+ method: 'GET',
283
+ headers: authorizedHeaders(this.config),
284
+ });
285
+ return response.user;
268
286
  });
269
- return res.user;
270
- };
271
- /**
272
- * Retrieves an app user by id, email, or refresh token.
273
- *
274
- * @example
275
- * try {
276
- * const user = await db.auth.getUser({ email })
277
- * console.log("Found user:", user)
278
- * } catch (err) {
279
- * console.error("Failed to retrieve user:", err.message);
280
- * }
281
- *
282
- * @see https://instantdb.com/docs/backend#retrieve-a-user
283
- */
284
- getUser = async (params) => {
285
- const qs = Object.entries(params)
286
- .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
287
- .join('&');
288
- const response = await jsonFetch(`${this.config.apiURI}/admin/users?${qs}`, {
289
- method: 'GET',
290
- headers: authorizedHeaders(this.config),
287
+ /**
288
+ * Deletes an app user by id, email, or refresh token.
289
+ *
290
+ * NB: This _only_ deletes the user; it does not delete all user data.
291
+ * You will need to handle this manually.
292
+ *
293
+ * @example
294
+ * try {
295
+ * const deletedUser = await db.auth.deleteUser({ email })
296
+ * console.log("Deleted user:", deletedUser)
297
+ * } catch (err) {
298
+ * console.error("Failed to delete user:", err.message);
299
+ * }
300
+ *
301
+ * @see https://instantdb.com/docs/backend#delete-a-user
302
+ */
303
+ this.deleteUser = (params) => __awaiter(this, void 0, void 0, function* () {
304
+ const qs = Object.entries(params).map(([k, v]) => `${k}=${v}`);
305
+ const response = yield jsonFetch(`${this.config.apiURI}/admin/users?${qs}`, {
306
+ method: 'DELETE',
307
+ headers: authorizedHeaders(this.config),
308
+ });
309
+ return response.deleted;
291
310
  });
292
- return response.user;
293
- };
294
- /**
295
- * Deletes an app user by id, email, or refresh token.
296
- *
297
- * NB: This _only_ deletes the user; it does not delete all user data.
298
- * You will need to handle this manually.
299
- *
300
- * @example
301
- * try {
302
- * const deletedUser = await db.auth.deleteUser({ email })
303
- * console.log("Deleted user:", deletedUser)
304
- * } catch (err) {
305
- * console.error("Failed to delete user:", err.message);
306
- * }
307
- *
308
- * @see https://instantdb.com/docs/backend#delete-a-user
309
- */
310
- deleteUser = async (params) => {
311
- const qs = Object.entries(params).map(([k, v]) => `${k}=${v}`);
312
- const response = await jsonFetch(`${this.config.apiURI}/admin/users?${qs}`, {
313
- method: 'DELETE',
314
- headers: authorizedHeaders(this.config),
311
+ this.config = config;
312
+ this.createToken = this.createToken.bind(this);
313
+ }
314
+ createToken(input) {
315
+ return __awaiter(this, void 0, void 0, function* () {
316
+ const body = typeof input === 'string' ? { email: input } : input;
317
+ const ret = yield jsonFetch(`${this.config.apiURI}/admin/refresh_tokens`, {
318
+ method: 'POST',
319
+ headers: authorizedHeaders(this.config),
320
+ body: JSON.stringify(body),
321
+ });
322
+ return ret.user.refresh_token;
315
323
  });
316
- return response.deleted;
317
- };
318
- async signOut(input) {
319
- // If input is a string, we assume it's an email.
320
- // This is because of backwards compatibility: we used to only
321
- // accept email strings. Eventually we can remove this
322
- const params = typeof input === 'string' ? { email: input } : input;
323
- const config = this.config;
324
- await jsonFetch(`${config.apiURI}/admin/sign_out`, {
325
- method: 'POST',
326
- headers: authorizedHeaders(config),
327
- body: JSON.stringify(params),
324
+ }
325
+ signOut(input) {
326
+ return __awaiter(this, void 0, void 0, function* () {
327
+ // If input is a string, we assume it's an email.
328
+ // This is because of backwards compatibility: we used to only
329
+ // accept email strings. Eventually we can remove this
330
+ const params = typeof input === 'string' ? { email: input } : input;
331
+ const config = this.config;
332
+ yield jsonFetch(`${config.apiURI}/admin/sign_out`, {
333
+ method: 'POST',
334
+ headers: authorizedHeaders(config),
335
+ body: JSON.stringify(params),
336
+ });
328
337
  });
329
338
  }
330
339
  }
@@ -337,137 +346,127 @@ const isWebReadable = (v) => v && typeof v.getReader === 'function';
337
346
  * Functions to manage file storage.
338
347
  */
339
348
  class Storage {
340
- config;
341
- impersonationOpts;
342
349
  constructor(config, impersonationOpts) {
343
- this.config = config;
344
- this.impersonationOpts = impersonationOpts;
345
- }
346
- /**
347
- * Uploads file at the provided path. Accepts a Buffer or a Readable stream.
348
- *
349
- * @see https://instantdb.com/docs/storage
350
- * @example
351
- * const buffer = fs.readFileSync('demo.png');
352
- * const isSuccess = await db.storage.uploadFile('photos/demo.png', buffer);
353
- */
354
- uploadFile = async (path, file, metadata = {}) => {
355
- const headers = {
356
- ...authorizedHeaders(this.config, this.impersonationOpts),
357
- path,
358
- };
359
- if (metadata.contentDisposition) {
360
- headers['content-disposition'] = metadata.contentDisposition;
361
- }
362
- // headers.content-type will become "undefined" (string)
363
- // if not removed from the object
364
- delete headers['content-type'];
365
- if (metadata.contentType) {
366
- headers['content-type'] = metadata.contentType;
367
- }
368
- let duplex;
369
- if (isNodeReadable(file)) {
370
- duplex = 'half'; // one-way stream
371
- }
372
- if (isNodeReadable(file) || isWebReadable(file)) {
373
- if (!metadata.fileSize) {
374
- throw new Error('fileSize is required in metadata when uploading streams');
350
+ /**
351
+ * Uploads file at the provided path. Accepts a Buffer or a Readable stream.
352
+ *
353
+ * @see https://instantdb.com/docs/storage
354
+ * @example
355
+ * const buffer = fs.readFileSync('demo.png');
356
+ * const isSuccess = await db.storage.uploadFile('photos/demo.png', buffer);
357
+ */
358
+ this.uploadFile = (path_1, file_1, ...args_1) => __awaiter(this, [path_1, file_1, ...args_1], void 0, function* (path, file, metadata = {}) {
359
+ const headers = Object.assign(Object.assign({}, authorizedHeaders(this.config, this.impersonationOpts)), { path });
360
+ if (metadata.contentDisposition) {
361
+ headers['content-disposition'] = metadata.contentDisposition;
375
362
  }
376
- headers['content-length'] = metadata.fileSize.toString();
377
- }
378
- let options = {
379
- method: 'PUT',
380
- headers,
381
- body: file,
382
- ...(duplex && { duplex }),
383
- };
384
- return jsonFetch(`${this.config.apiURI}/admin/storage/upload`, options);
385
- };
386
- /**
387
- * Deletes a file by its path name (e.g. "photos/demo.png").
388
- *
389
- * @see https://instantdb.com/docs/storage
390
- * @example
391
- * await db.storage.delete("photos/demo.png");
392
- */
393
- delete = async (pathname) => {
394
- return jsonFetch(`${this.config.apiURI}/admin/storage/files?filename=${encodeURIComponent(pathname)}`, {
395
- method: 'DELETE',
396
- headers: authorizedHeaders(this.config, this.impersonationOpts),
363
+ // headers.content-type will become "undefined" (string)
364
+ // if not removed from the object
365
+ delete headers['content-type'];
366
+ if (metadata.contentType) {
367
+ headers['content-type'] = metadata.contentType;
368
+ }
369
+ let duplex;
370
+ if (isNodeReadable(file)) {
371
+ duplex = 'half'; // one-way stream
372
+ }
373
+ if (isNodeReadable(file) || isWebReadable(file)) {
374
+ if (!metadata.fileSize) {
375
+ throw new Error('fileSize is required in metadata when uploading streams');
376
+ }
377
+ headers['content-length'] = metadata.fileSize.toString();
378
+ }
379
+ let options = Object.assign({ method: 'PUT', headers, body: file }, (duplex && { duplex }));
380
+ return jsonFetch(`${this.config.apiURI}/admin/storage/upload`, options);
397
381
  });
398
- };
399
- /**
400
- * Deletes multiple files by their path names (e.g. "photos/demo.png", "essays/demo.txt").
401
- *
402
- * @see https://instantdb.com/docs/storage
403
- * @example
404
- * await db.storage.deleteMany(["images/1.png", "images/2.png", "images/3.png"]);
405
- */
406
- deleteMany = async (pathnames) => {
407
- return jsonFetch(`${this.config.apiURI}/admin/storage/files/delete`, {
408
- method: 'POST',
409
- headers: authorizedHeaders(this.config, this.impersonationOpts),
410
- body: JSON.stringify({ filenames: pathnames }),
382
+ /**
383
+ * Deletes a file by its path name (e.g. "photos/demo.png").
384
+ *
385
+ * @see https://instantdb.com/docs/storage
386
+ * @example
387
+ * await db.storage.delete("photos/demo.png");
388
+ */
389
+ this.delete = (pathname) => __awaiter(this, void 0, void 0, function* () {
390
+ return jsonFetch(`${this.config.apiURI}/admin/storage/files?filename=${encodeURIComponent(pathname)}`, {
391
+ method: 'DELETE',
392
+ headers: authorizedHeaders(this.config, this.impersonationOpts),
393
+ });
411
394
  });
412
- };
413
- /**
414
- * @deprecated. This method will be removed in the future. Use `uploadFile`
415
- * instead
416
- */
417
- upload = async (pathname, file, metadata = {}) => {
418
- const { data: presignedUrl } = await jsonFetch(`${this.config.apiURI}/admin/storage/signed-upload-url`, {
419
- method: 'POST',
420
- headers: authorizedHeaders(this.config),
421
- body: JSON.stringify({
422
- app_id: this.config.appId,
423
- filename: pathname,
424
- }),
395
+ /**
396
+ * Deletes multiple files by their path names (e.g. "photos/demo.png", "essays/demo.txt").
397
+ *
398
+ * @see https://instantdb.com/docs/storage
399
+ * @example
400
+ * await db.storage.deleteMany(["images/1.png", "images/2.png", "images/3.png"]);
401
+ */
402
+ this.deleteMany = (pathnames) => __awaiter(this, void 0, void 0, function* () {
403
+ return jsonFetch(`${this.config.apiURI}/admin/storage/files/delete`, {
404
+ method: 'POST',
405
+ headers: authorizedHeaders(this.config, this.impersonationOpts),
406
+ body: JSON.stringify({ filenames: pathnames }),
407
+ });
425
408
  });
426
- const headers = {};
427
- const contentType = metadata.contentType;
428
- if (contentType) {
429
- headers['Content-Type'] = contentType;
430
- }
431
- const { ok } = await fetch(presignedUrl, {
432
- method: 'PUT',
433
- body: file,
434
- headers,
409
+ /**
410
+ * @deprecated. This method will be removed in the future. Use `uploadFile`
411
+ * instead
412
+ */
413
+ this.upload = (pathname_1, file_1, ...args_1) => __awaiter(this, [pathname_1, file_1, ...args_1], void 0, function* (pathname, file, metadata = {}) {
414
+ const { data: presignedUrl } = yield jsonFetch(`${this.config.apiURI}/admin/storage/signed-upload-url`, {
415
+ method: 'POST',
416
+ headers: authorizedHeaders(this.config),
417
+ body: JSON.stringify({
418
+ app_id: this.config.appId,
419
+ filename: pathname,
420
+ }),
421
+ });
422
+ const headers = {};
423
+ const contentType = metadata.contentType;
424
+ if (contentType) {
425
+ headers['Content-Type'] = contentType;
426
+ }
427
+ const { ok } = yield fetch(presignedUrl, {
428
+ method: 'PUT',
429
+ body: file,
430
+ headers,
431
+ });
432
+ return ok;
435
433
  });
436
- return ok;
437
- };
438
- /**
439
- * @deprecated. This method will be removed in the future. Use `query` instead
440
- * @example
441
- * const files = await db.query({ $files: {}})
442
- */
443
- list = async () => {
444
- const { data } = await jsonFetch(`${this.config.apiURI}/admin/storage/files`, {
445
- method: 'GET',
446
- headers: authorizedHeaders(this.config),
434
+ /**
435
+ * @deprecated. This method will be removed in the future. Use `query` instead
436
+ * @example
437
+ * const files = await db.query({ $files: {}})
438
+ */
439
+ this.list = () => __awaiter(this, void 0, void 0, function* () {
440
+ const { data } = yield jsonFetch(`${this.config.apiURI}/admin/storage/files`, {
441
+ method: 'GET',
442
+ headers: authorizedHeaders(this.config),
443
+ });
444
+ return data;
447
445
  });
448
- return data;
449
- };
450
- /**
451
- * @deprecated. getDownloadUrl will be removed in the future.
452
- * Use `query` instead to query and fetch for valid urls
453
- *
454
- * db.useQuery({
455
- * $files: {
456
- * $: {
457
- * where: {
458
- * path: "moop.png"
459
- * }
460
- * }
461
- * }
462
- * })
463
- */
464
- getDownloadUrl = async (pathname) => {
465
- const { data } = await jsonFetch(`${this.config.apiURI}/admin/storage/signed-download-url?app_id=${this.config.appId}&filename=${encodeURIComponent(pathname)}`, {
466
- method: 'GET',
467
- headers: authorizedHeaders(this.config),
446
+ /**
447
+ * @deprecated. getDownloadUrl will be removed in the future.
448
+ * Use `query` instead to query and fetch for valid urls
449
+ *
450
+ * db.useQuery({
451
+ * $files: {
452
+ * $: {
453
+ * where: {
454
+ * path: "moop.png"
455
+ * }
456
+ * }
457
+ * }
458
+ * })
459
+ */
460
+ this.getDownloadUrl = (pathname) => __awaiter(this, void 0, void 0, function* () {
461
+ const { data } = yield jsonFetch(`${this.config.apiURI}/admin/storage/signed-download-url?app_id=${this.config.appId}&filename=${encodeURIComponent(pathname)}`, {
462
+ method: 'GET',
463
+ headers: authorizedHeaders(this.config),
464
+ });
465
+ return data;
468
466
  });
469
- return data;
470
- };
467
+ this.config = config;
468
+ this.impersonationOpts = impersonationOpts;
469
+ }
471
470
  }
472
471
  /**
473
472
  *
@@ -479,72 +478,158 @@ class Storage {
479
478
  * const db = init({ appId: "my-app-id", adminToken: "my-admin-token" })
480
479
  */
481
480
  class InstantAdminDatabase {
482
- config;
483
- auth;
484
- storage;
485
- rooms;
486
- impersonationOpts;
487
- tx = txInit();
488
481
  constructor(_config) {
482
+ this.tx = txInit();
483
+ /**
484
+ * Sometimes you want to scope queries to a specific user.
485
+ *
486
+ * You can provide a user's auth token, email, or impersonate a guest.
487
+ *
488
+ * @see https://instantdb.com/docs/backend#impersonating-users
489
+ * @example
490
+ * await db.asUser({email: "stopa@instantdb.com"}).query({ goals: {} })
491
+ */
492
+ this.asUser = (opts) => {
493
+ const newClient = new InstantAdminDatabase(Object.assign({}, this.config));
494
+ newClient.impersonationOpts = opts;
495
+ newClient.storage = new Storage(this.config, opts);
496
+ return newClient;
497
+ };
498
+ /**
499
+ * Use this to query your data!
500
+ *
501
+ * @see https://instantdb.com/docs/instaql
502
+ *
503
+ * @example
504
+ * // fetch all goals
505
+ * await db.query({ goals: {} })
506
+ *
507
+ * // goals where the title is "Get Fit"
508
+ * await db.query({ goals: { $: { where: { title: "Get Fit" } } } })
509
+ *
510
+ * // all goals, _alongside_ their todos
511
+ * await db.query({ goals: { todos: {} } })
512
+ */
513
+ this.query = (query, opts = {}) => {
514
+ if (query && opts && 'ruleParams' in opts) {
515
+ query = Object.assign({ $$ruleParams: opts['ruleParams'] }, query);
516
+ }
517
+ if (!this.config.disableValidation) {
518
+ validateQuery(query, this.config.schema);
519
+ }
520
+ const fetchOpts = opts.fetchOpts || {};
521
+ const fetchOptsHeaders = fetchOpts['headers'] || {};
522
+ return jsonFetch(`${this.config.apiURI}/admin/query`, Object.assign(Object.assign({}, fetchOpts), { method: 'POST', headers: Object.assign(Object.assign({}, fetchOptsHeaders), authorizedHeaders(this.config, this.impersonationOpts)), body: JSON.stringify({
523
+ query: query,
524
+ 'inference?': !!this.config.schema,
525
+ }) }));
526
+ };
527
+ /**
528
+ * Use this to write data! You can create, update, delete, and link objects
529
+ *
530
+ * @see https://instantdb.com/docs/instaml
531
+ *
532
+ * @example
533
+ * // Create a new object in the `goals` namespace
534
+ * const goalId = id();
535
+ * db.transact(db.tx.goals[goalId].update({title: "Get fit"}))
536
+ *
537
+ * // Update the title
538
+ * db.transact(db.tx.goals[goalId].update({title: "Get super fit"}))
539
+ *
540
+ * // Delete it
541
+ * db.transact(db.tx.goals[goalId].delete())
542
+ *
543
+ * // Or create an association:
544
+ * todoId = id();
545
+ * db.transact([
546
+ * db.tx.todos[todoId].update({ title: 'Go on a run' }),
547
+ * db.tx.goals[goalId].link({todos: todoId}),
548
+ * ])
549
+ */
550
+ this.transact = (inputChunks) => {
551
+ if (!this.config.disableValidation) {
552
+ validateTransactions(inputChunks, this.config.schema);
553
+ }
554
+ return jsonFetch(`${this.config.apiURI}/admin/transact`, {
555
+ method: 'POST',
556
+ headers: authorizedHeaders(this.config, this.impersonationOpts),
557
+ body: JSON.stringify({
558
+ steps: steps(inputChunks),
559
+ 'throw-on-missing-attrs?': !!this.config.schema,
560
+ }),
561
+ });
562
+ };
563
+ /**
564
+ * Like `query`, but returns debugging information
565
+ * for permissions checks along with the result.
566
+ * Useful for inspecting the values returned by the permissions checks.
567
+ * Note, this will return debug information for *all* entities
568
+ * that match the query's `where` clauses.
569
+ *
570
+ * Requires a user/guest context to be set with `asUser`,
571
+ * since permissions checks are user-specific.
572
+ *
573
+ * Accepts an optional configuration object with a `rules` key.
574
+ * The provided rules will override the rules in the database for the query.
575
+ *
576
+ * @see https://instantdb.com/docs/instaql
577
+ *
578
+ * @example
579
+ * await db.asUser({ guest: true }).debugQuery(
580
+ * { goals: {} },
581
+ * { rules: { goals: { allow: { read: "auth.id != null" } } }
582
+ * )
583
+ */
584
+ this.debugQuery = (query, opts) => __awaiter(this, void 0, void 0, function* () {
585
+ if (query && opts && 'ruleParams' in opts) {
586
+ query = Object.assign({ $$ruleParams: opts['ruleParams'] }, query);
587
+ }
588
+ const response = yield jsonFetch(`${this.config.apiURI}/admin/query_perms_check`, {
589
+ method: 'POST',
590
+ headers: authorizedHeaders(this.config, this.impersonationOpts),
591
+ body: JSON.stringify({ query, 'rules-override': opts === null || opts === void 0 ? void 0 : opts.rules }),
592
+ });
593
+ return {
594
+ result: response.result,
595
+ checkResults: response['check-results'],
596
+ };
597
+ });
598
+ /**
599
+ * Like `transact`, but does not write to the database.
600
+ * Returns debugging information for permissions checks.
601
+ * Useful for inspecting the values returned by the permissions checks.
602
+ *
603
+ * Requires a user/guest context to be set with `asUser`,
604
+ * since permissions checks are user-specific.
605
+ *
606
+ * Accepts an optional configuration object with a `rules` key.
607
+ * The provided rules will override the rules in the database for the duration of the transaction.
608
+ *
609
+ * @example
610
+ * const goalId = id();
611
+ * db.asUser({ guest: true }).debugTransact(
612
+ * [db.tx.goals[goalId].update({title: "Get fit"})],
613
+ * { rules: { goals: { allow: { update: "auth.id != null" } } }
614
+ * )
615
+ */
616
+ this.debugTransact = (inputChunks, opts) => {
617
+ return jsonFetch(`${this.config.apiURI}/admin/transact_perms_check`, {
618
+ method: 'POST',
619
+ headers: authorizedHeaders(this.config, this.impersonationOpts),
620
+ body: JSON.stringify({
621
+ steps: steps(inputChunks),
622
+ 'rules-override': opts === null || opts === void 0 ? void 0 : opts.rules,
623
+ // @ts-expect-error because we're using a private API (for now)
624
+ 'dangerously-commit-tx': opts === null || opts === void 0 ? void 0 : opts.__dangerouslyCommit,
625
+ }),
626
+ });
627
+ };
489
628
  this.config = instantConfigWithDefaults(_config);
490
629
  this.auth = new Auth(this.config);
491
630
  this.storage = new Storage(this.config, this.impersonationOpts);
492
631
  this.rooms = new Rooms(this.config);
493
632
  }
494
- /**
495
- * Sometimes you want to scope queries to a specific user.
496
- *
497
- * You can provide a user's auth token, email, or impersonate a guest.
498
- *
499
- * @see https://instantdb.com/docs/backend#impersonating-users
500
- * @example
501
- * await db.asUser({email: "stopa@instantdb.com"}).query({ goals: {} })
502
- */
503
- asUser = (opts) => {
504
- const newClient = new InstantAdminDatabase({
505
- ...this.config,
506
- });
507
- newClient.impersonationOpts = opts;
508
- newClient.storage = new Storage(this.config, opts);
509
- return newClient;
510
- };
511
- /**
512
- * Use this to query your data!
513
- *
514
- * @see https://instantdb.com/docs/instaql
515
- *
516
- * @example
517
- * // fetch all goals
518
- * await db.query({ goals: {} })
519
- *
520
- * // goals where the title is "Get Fit"
521
- * await db.query({ goals: { $: { where: { title: "Get Fit" } } } })
522
- *
523
- * // all goals, _alongside_ their todos
524
- * await db.query({ goals: { todos: {} } })
525
- */
526
- query = (query, opts = {}) => {
527
- if (query && opts && 'ruleParams' in opts) {
528
- query = { $$ruleParams: opts['ruleParams'], ...query };
529
- }
530
- if (!this.config.disableValidation) {
531
- validateQuery(query, this.config.schema);
532
- }
533
- const fetchOpts = opts.fetchOpts || {};
534
- const fetchOptsHeaders = fetchOpts['headers'] || {};
535
- return jsonFetch(`${this.config.apiURI}/admin/query`, {
536
- ...fetchOpts,
537
- method: 'POST',
538
- headers: {
539
- ...fetchOptsHeaders,
540
- ...authorizedHeaders(this.config, this.impersonationOpts),
541
- },
542
- body: JSON.stringify({
543
- query: query,
544
- 'inference?': !!this.config.schema,
545
- }),
546
- });
547
- };
548
633
  /**
549
634
  * Use this to to get a live view of your data!
550
635
  *
@@ -582,17 +667,14 @@ class InstantAdminDatabase {
582
667
  */
583
668
  subscribeQuery(query, cb, opts = {}) {
584
669
  if (query && opts && 'ruleParams' in opts) {
585
- query = { $$ruleParams: opts['ruleParams'], ...query };
670
+ query = Object.assign({ $$ruleParams: opts['ruleParams'] }, query);
586
671
  }
587
672
  if (!this.config.disableValidation) {
588
673
  validateQuery(query, this.config.schema);
589
674
  }
590
675
  const fetchOpts = opts.fetchOpts || {};
591
676
  const fetchOptsHeaders = fetchOpts['headers'] || {};
592
- const headers = {
593
- ...fetchOptsHeaders,
594
- ...authorizedHeaders(this.config, this.impersonationOpts),
595
- };
677
+ const headers = Object.assign(Object.assign({}, fetchOptsHeaders), authorizedHeaders(this.config, this.impersonationOpts));
596
678
  const inference = !!this.config.schema;
597
679
  return subscribe(query, cb, {
598
680
  headers,
@@ -600,107 +682,6 @@ class InstantAdminDatabase {
600
682
  apiURI: this.config.apiURI,
601
683
  });
602
684
  }
603
- /**
604
- * Use this to write data! You can create, update, delete, and link objects
605
- *
606
- * @see https://instantdb.com/docs/instaml
607
- *
608
- * @example
609
- * // Create a new object in the `goals` namespace
610
- * const goalId = id();
611
- * db.transact(db.tx.goals[goalId].update({title: "Get fit"}))
612
- *
613
- * // Update the title
614
- * db.transact(db.tx.goals[goalId].update({title: "Get super fit"}))
615
- *
616
- * // Delete it
617
- * db.transact(db.tx.goals[goalId].delete())
618
- *
619
- * // Or create an association:
620
- * todoId = id();
621
- * db.transact([
622
- * db.tx.todos[todoId].update({ title: 'Go on a run' }),
623
- * db.tx.goals[goalId].link({todos: todoId}),
624
- * ])
625
- */
626
- transact = (inputChunks) => {
627
- if (!this.config.disableValidation) {
628
- validateTransactions(inputChunks, this.config.schema);
629
- }
630
- return jsonFetch(`${this.config.apiURI}/admin/transact`, {
631
- method: 'POST',
632
- headers: authorizedHeaders(this.config, this.impersonationOpts),
633
- body: JSON.stringify({
634
- steps: steps(inputChunks),
635
- 'throw-on-missing-attrs?': !!this.config.schema,
636
- }),
637
- });
638
- };
639
- /**
640
- * Like `query`, but returns debugging information
641
- * for permissions checks along with the result.
642
- * Useful for inspecting the values returned by the permissions checks.
643
- * Note, this will return debug information for *all* entities
644
- * that match the query's `where` clauses.
645
- *
646
- * Requires a user/guest context to be set with `asUser`,
647
- * since permissions checks are user-specific.
648
- *
649
- * Accepts an optional configuration object with a `rules` key.
650
- * The provided rules will override the rules in the database for the query.
651
- *
652
- * @see https://instantdb.com/docs/instaql
653
- *
654
- * @example
655
- * await db.asUser({ guest: true }).debugQuery(
656
- * { goals: {} },
657
- * { rules: { goals: { allow: { read: "auth.id != null" } } }
658
- * )
659
- */
660
- debugQuery = async (query, opts) => {
661
- if (query && opts && 'ruleParams' in opts) {
662
- query = { $$ruleParams: opts['ruleParams'], ...query };
663
- }
664
- const response = await jsonFetch(`${this.config.apiURI}/admin/query_perms_check`, {
665
- method: 'POST',
666
- headers: authorizedHeaders(this.config, this.impersonationOpts),
667
- body: JSON.stringify({ query, 'rules-override': opts?.rules }),
668
- });
669
- return {
670
- result: response.result,
671
- checkResults: response['check-results'],
672
- };
673
- };
674
- /**
675
- * Like `transact`, but does not write to the database.
676
- * Returns debugging information for permissions checks.
677
- * Useful for inspecting the values returned by the permissions checks.
678
- *
679
- * Requires a user/guest context to be set with `asUser`,
680
- * since permissions checks are user-specific.
681
- *
682
- * Accepts an optional configuration object with a `rules` key.
683
- * The provided rules will override the rules in the database for the duration of the transaction.
684
- *
685
- * @example
686
- * const goalId = id();
687
- * db.asUser({ guest: true }).debugTransact(
688
- * [db.tx.goals[goalId].update({title: "Get fit"})],
689
- * { rules: { goals: { allow: { update: "auth.id != null" } } }
690
- * )
691
- */
692
- debugTransact = (inputChunks, opts) => {
693
- return jsonFetch(`${this.config.apiURI}/admin/transact_perms_check`, {
694
- method: 'POST',
695
- headers: authorizedHeaders(this.config, this.impersonationOpts),
696
- body: JSON.stringify({
697
- steps: steps(inputChunks),
698
- 'rules-override': opts?.rules,
699
- // @ts-expect-error because we're using a private API (for now)
700
- 'dangerously-commit-tx': opts?.__dangerouslyCommit,
701
- }),
702
- });
703
- };
704
685
  }
705
686
  export { init, init_experimental, id, tx, lookup, i, createInstantRouteHandler,
706
687
  // error