@axium/storage 0.2.0 → 0.2.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/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type Schema } from '@axium/server/database';
2
- import type { ExpressionBuilder, Generated, Selectable } from 'kysely';
2
+ import type { Generated, Selectable } from 'kysely';
3
3
  import type { StorageItemMetadata, StorageLimits, StorageUsage } from './common.js';
4
4
  import './polyfills.js';
5
5
  declare module '@axium/server/database' {
@@ -53,15 +53,12 @@ declare module '@axium/server/config' {
53
53
  export interface StorageItem extends StorageItemMetadata {
54
54
  data: Uint8Array<ArrayBufferLike>;
55
55
  }
56
- export declare function parseItem<T extends Record<string, unknown> = Record<string, unknown>>(item: Selectable<Schema['storage']> & {
57
- hash: string;
58
- }): StorageItemMetadata<T>;
56
+ export declare function parseItem<T extends Record<string, unknown> = Record<string, unknown>>(item: Selectable<Schema['storage']>): StorageItemMetadata<T>;
59
57
  /**
60
58
  * Returns the current usage of the storage for a user in bytes.
61
59
  */
62
60
  export declare function currentUsage(userId: string): Promise<StorageUsage>;
63
61
  export declare function get<T extends Record<string, unknown> = Record<string, unknown>>(itemId: string): Promise<StorageItemMetadata<T>>;
64
- export declare function withEncodedHash(eb: ExpressionBuilder<Schema, 'storage'>): import("kysely").AliasedExpression<string, "hash">;
65
62
  export type ExternalLimitHandler = (userId?: string) => StorageLimits | Promise<StorageLimits>;
66
63
  /**
67
64
  * Define the handler to get limits for a user externally.
package/dist/server.js CHANGED
@@ -1,8 +1,9 @@
1
- import { getSessionAndUser } from '@axium/server/auth';
1
+ import { Permission } from '@axium/core/access';
2
+ import { checkAuthForItem, checkAuthForUser, getSessionAndUser } from '@axium/server/auth';
2
3
  import { addConfigDefaults, config } from '@axium/server/config';
3
4
  import { connect, database, expectedTypes } from '@axium/server/database';
4
5
  import { dirs } from '@axium/server/io';
5
- import { checkAuth, getToken, parseBody, withError } from '@axium/server/requests';
6
+ import { getToken, parseBody, withError } from '@axium/server/requests';
6
7
  import { addRoute } from '@axium/server/routes';
7
8
  import { error } from '@sveltejs/kit';
8
9
  import { createHash } from 'node:crypto';
@@ -52,6 +53,7 @@ export function parseItem(item) {
52
53
  ...item,
53
54
  metadata: item.metadata,
54
55
  dataURL: `/raw/storage/${item.id}`,
56
+ hash: item.hash.toHex(),
55
57
  };
56
58
  }
57
59
  /**
@@ -73,13 +75,10 @@ export async function get(itemId) {
73
75
  .selectFrom('storage')
74
76
  .where('id', '=', itemId)
75
77
  .selectAll()
76
- .select(withEncodedHash)
78
+ .$narrowType()
77
79
  .executeTakeFirstOrThrow();
78
80
  return parseItem(result);
79
81
  }
80
- export function withEncodedHash(eb) {
81
- return eb.fn('encode', ['hash', eb.val('hex')]).as('hash');
82
- }
83
82
  let _getLimits = null;
84
83
  /**
85
84
  * Define the handler to get limits for a user externally.
@@ -102,21 +101,15 @@ addRoute({
102
101
  if (!config.storage.enabled)
103
102
  error(503, 'User storage is disabled');
104
103
  const itemId = event.params.id;
105
- const item = await get(itemId);
106
- if (!item)
107
- error(404, 'Item not found');
108
- await checkAuth(event, item.userId);
109
- return item;
104
+ const { item } = await checkAuthForItem(event, 'storage', itemId, Permission.Read);
105
+ return parseItem(item);
110
106
  },
111
107
  async PATCH(event) {
112
108
  if (!config.storage.enabled)
113
109
  error(503, 'User storage is disabled');
114
110
  const itemId = event.params.id;
115
111
  const body = await parseBody(event, StorageItemUpdate);
116
- const item = await get(itemId);
117
- if (!item)
118
- error(404, 'Item not found');
119
- await checkAuth(event, item.userId);
112
+ await checkAuthForItem(event, 'storage', itemId, Permission.Manage);
120
113
  const values = {};
121
114
  if ('publicPermission' in body)
122
115
  values.publicPermission = body.publicPermission;
@@ -133,7 +126,6 @@ addRoute({
133
126
  .where('id', '=', itemId)
134
127
  .set(values)
135
128
  .returningAll()
136
- .returning(withEncodedHash)
137
129
  .executeTakeFirstOrThrow()
138
130
  .catch(withError('Could not update item')));
139
131
  },
@@ -141,10 +133,8 @@ addRoute({
141
133
  if (!config.storage.enabled)
142
134
  error(503, 'User storage is disabled');
143
135
  const itemId = event.params.id;
144
- const item = await get(itemId);
145
- if (!item)
146
- error(404, 'Item not found');
147
- await checkAuth(event, item.userId);
136
+ const auth = await checkAuthForItem(event, 'storage', itemId, Permission.Manage);
137
+ const item = parseItem(auth.item);
148
138
  await database
149
139
  .deleteFrom('storage')
150
140
  .where('id', '=', itemId)
@@ -168,10 +158,7 @@ addRoute({
168
158
  if (!config.storage.enabled)
169
159
  error(503, 'User storage is disabled');
170
160
  const itemId = event.params.id;
171
- const item = await get(itemId);
172
- if (!item)
173
- error(404, 'Item not found');
174
- await checkAuth(event, item.userId);
161
+ const { item } = await checkAuthForItem(event, 'storage', itemId, Permission.Read);
175
162
  if (item.type != 'inode/directory')
176
163
  error(409, 'Item is not a directory');
177
164
  const items = await database
@@ -179,7 +166,6 @@ addRoute({
179
166
  .where('parentId', '=', itemId)
180
167
  .where('trashedAt', '!=', null)
181
168
  .selectAll()
182
- .select(withEncodedHash)
183
169
  .execute();
184
170
  return items.map(parseItem);
185
171
  },
@@ -228,7 +214,6 @@ addRoute({
228
214
  .insertInto('storage')
229
215
  .values({ userId: userId, hash, name, size, type, immutable: useCAS, parentId })
230
216
  .returningAll()
231
- .returning(withEncodedHash)
232
217
  .executeTakeFirstOrThrow()
233
218
  .catch(withError('Could not create item'));
234
219
  const path = join(config.storage.data, result.id);
@@ -257,10 +242,7 @@ addRoute({
257
242
  if (!config.storage.enabled)
258
243
  error(503, 'User storage is disabled');
259
244
  const itemId = event.params.id;
260
- const item = await get(itemId);
261
- if (!item)
262
- error(404, 'Item not found');
263
- await checkAuth(event, item.userId);
245
+ const { item } = await checkAuthForItem(event, 'storage', itemId, Permission.Read);
264
246
  if (item.trashedAt)
265
247
  error(410, 'Trashed items can not be downloaded');
266
248
  const content = new Uint8Array(readFileSync(join(config.storage.data, item.id)));
@@ -275,16 +257,11 @@ addRoute({
275
257
  if (!config.storage.enabled)
276
258
  error(503, 'User storage is disabled');
277
259
  const itemId = event.params.id;
278
- const item = await get(itemId);
279
- if (!item)
280
- error(404, 'Item not found');
281
- const { accessor } = await checkAuth(event, item.userId);
260
+ const { item } = await checkAuthForItem(event, 'storage', itemId, Permission.Edit);
282
261
  if (item.immutable)
283
262
  error(403, 'Item is immutable');
284
263
  if (item.trashedAt)
285
264
  error(410, 'Trashed items can not be changed');
286
- if (item.userId != accessor.id)
287
- error(403, 'Item editing is restricted to the owner');
288
265
  const type = event.request.headers.get('content-type') || 'application/octet-stream';
289
266
  // @todo: add this to the audit log
290
267
  if (type != item.type)
@@ -308,7 +285,6 @@ addRoute({
308
285
  .where('id', '=', itemId)
309
286
  .set({ size, modifiedAt: new Date(), hash })
310
287
  .returningAll()
311
- .returning(withEncodedHash)
312
288
  .executeTakeFirstOrThrow()
313
289
  .catch(withError('Could not update item'));
314
290
  await writeFile(join(config.storage.data, result.id), content).catch(withError('Could not write'));
@@ -322,7 +298,7 @@ addRoute({
322
298
  if (!config.storage.enabled)
323
299
  error(503, 'User storage is disabled');
324
300
  const userId = event.params.id;
325
- await checkAuth(event, userId);
301
+ await checkAuthForUser(event, userId);
326
302
  const [usage, limits] = await Promise.all([currentUsage(userId), getLimits(userId)]).catch(withError('Could not fetch data'));
327
303
  return { usage, limits };
328
304
  },
@@ -330,9 +306,9 @@ addRoute({
330
306
  if (!config.storage.enabled)
331
307
  error(503, 'User storage is disabled');
332
308
  const userId = event.params.id;
333
- await checkAuth(event, userId);
309
+ await checkAuthForUser(event, userId);
334
310
  const [items, usage, limits] = await Promise.all([
335
- database.selectFrom('storage').where('userId', '=', userId).selectAll().select(withEncodedHash).execute(),
311
+ database.selectFrom('storage').where('userId', '=', userId).selectAll().execute(),
336
312
  currentUsage(userId),
337
313
  getLimits(userId),
338
314
  ]).catch(withError('Could not fetch data'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axium/storage",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "author": "James Prevett <axium@jamespre.dev> (https://jamespre.dev)",
5
5
  "description": "User file storage for Axium",
6
6
  "funding": {
@@ -33,7 +33,7 @@
33
33
  "peerDependencies": {
34
34
  "@axium/client": ">=0.1.0",
35
35
  "@axium/core": ">=0.5.0",
36
- "@axium/server": ">=0.17.0",
36
+ "@axium/server": ">=0.18.0",
37
37
  "@sveltejs/kit": "^2.23.0",
38
38
  "utilium": "^2.3.8"
39
39
  },