@appsemble/node-utils 0.20.45 → 0.21.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.
Files changed (104) hide show
  1. package/README.md +3 -3
  2. package/app.d.ts +17 -0
  3. package/app.js +49 -0
  4. package/csv.d.ts +2 -0
  5. package/csv.js +55 -0
  6. package/fs.d.ts +3 -3
  7. package/fs.js +1 -1
  8. package/fs.test.js +5 -5
  9. package/getAppsembleMessages.d.ts +9 -0
  10. package/getAppsembleMessages.js +32 -0
  11. package/handleError.test.js +4 -4
  12. package/icon.d.ts +44 -0
  13. package/icon.js +69 -0
  14. package/index.d.ts +22 -1
  15. package/index.js +22 -1
  16. package/interceptors.test.js +5 -6
  17. package/jsonschema.d.ts +2 -0
  18. package/jsonschema.js +7 -0
  19. package/koa.d.ts +6 -0
  20. package/koa.js +27 -0
  21. package/logger.js +1 -1
  22. package/mergeMessages.d.ts +9 -0
  23. package/mergeMessages.js +17 -0
  24. package/middleware/boom.d.ts +7 -0
  25. package/middleware/boom.js +32 -0
  26. package/middleware/boom.test.js +58 -0
  27. package/middleware/conditional.d.ts +2 -0
  28. package/middleware/conditional.js +9 -0
  29. package/middleware/frontend.d.ts +3 -0
  30. package/middleware/frontend.js +40 -0
  31. package/{loggerMiddleware.js → middleware/loggerMiddleware.js} +1 -1
  32. package/{loggerMiddleware.test.js → middleware/loggerMiddleware.test.js} +14 -15
  33. package/odata.d.ts +18 -0
  34. package/odata.js +45 -0
  35. package/organizationBlocklist.d.ts +4 -0
  36. package/organizationBlocklist.js +5 -0
  37. package/package.json +45 -5
  38. package/parsers.d.ts +3 -0
  39. package/parsers.js +18 -0
  40. package/readAsset.d.ts +13 -0
  41. package/readAsset.js +6 -0
  42. package/readFileOrString.d.ts +1 -1
  43. package/render.d.ts +21 -0
  44. package/render.js +46 -0
  45. package/resource.d.ts +43 -0
  46. package/resource.js +172 -0
  47. package/scim.d.ts +26 -0
  48. package/scim.js +32 -0
  49. package/server/controllers/action.d.ts +7 -0
  50. package/server/controllers/action.js +129 -0
  51. package/server/controllers/appMembers.d.ts +3 -0
  52. package/server/controllers/appMembers.js +19 -0
  53. package/server/controllers/appMessages.d.ts +3 -0
  54. package/server/controllers/appMessages.js +75 -0
  55. package/server/controllers/assets.d.ts +5 -0
  56. package/server/controllers/assets.js +74 -0
  57. package/server/controllers/index.d.ts +7 -0
  58. package/server/controllers/index.js +8 -0
  59. package/server/controllers/oauth2Provider.d.ts +3 -0
  60. package/server/controllers/oauth2Provider.js +7 -0
  61. package/server/controllers/resources.d.ts +8 -0
  62. package/server/controllers/resources.js +273 -0
  63. package/server/controllers/resources.test.d.ts +1 -0
  64. package/server/controllers/resources.test.js +552 -0
  65. package/server/controllers/teams.d.ts +3 -0
  66. package/server/controllers/teams.js +12 -0
  67. package/server/routes/appRouter/blockAssetHandler.d.ts +3 -0
  68. package/server/routes/appRouter/blockAssetHandler.js +13 -0
  69. package/server/routes/appRouter/blockCssHandler.d.ts +3 -0
  70. package/server/routes/appRouter/blockCssHandler.js +15 -0
  71. package/server/routes/appRouter/bulmaHandler.d.ts +3 -0
  72. package/server/routes/appRouter/bulmaHandler.js +118 -0
  73. package/server/routes/appRouter/cssHandler.d.ts +3 -0
  74. package/server/routes/appRouter/cssHandler.js +12 -0
  75. package/server/routes/appRouter/iconHandler.d.ts +3 -0
  76. package/server/routes/appRouter/iconHandler.js +23 -0
  77. package/server/routes/appRouter/index.d.ts +3 -0
  78. package/server/routes/appRouter/index.js +85 -0
  79. package/server/routes/appRouter/indexHandler.d.ts +5 -0
  80. package/server/routes/appRouter/indexHandler.js +69 -0
  81. package/server/routes/appRouter/manifestHandler.d.ts +3 -0
  82. package/server/routes/appRouter/manifestHandler.js +47 -0
  83. package/server/routes/appRouter/robotsHandler.d.ts +2 -0
  84. package/server/routes/appRouter/robotsHandler.js +6 -0
  85. package/server/routes/appRouter/screenshotHandler.d.ts +3 -0
  86. package/server/routes/appRouter/screenshotHandler.js +19 -0
  87. package/server/routes/appRouter/serviceWorkerHandler.d.ts +3 -0
  88. package/server/routes/appRouter/serviceWorkerHandler.js +18 -0
  89. package/server/routes/appRouter/staticHandler.d.ts +2 -0
  90. package/server/routes/appRouter/staticHandler.js +9 -0
  91. package/server/types.d.ts +356 -0
  92. package/server/types.js +2 -0
  93. package/testFixtures.d.ts +3 -3
  94. package/testFixtures.js +1 -1
  95. package/tinyRouter.d.ts +16 -0
  96. package/tinyRouter.js +34 -0
  97. package/tinyRouter.test.d.ts +1 -0
  98. package/tinyRouter.test.js +85 -0
  99. package/vitest.config.d.ts +2 -0
  100. package/vitest.setup.d.ts +1 -0
  101. package/{jest.setup.js → vitest.setup.js} +1 -1
  102. /package/{jest.setup.d.ts → middleware/boom.test.d.ts} +0 -0
  103. /package/{loggerMiddleware.d.ts → middleware/loggerMiddleware.d.ts} +0 -0
  104. /package/{loggerMiddleware.test.d.ts → middleware/loggerMiddleware.test.d.ts} +0 -0
@@ -0,0 +1,552 @@
1
+ import { defaultLocale, remap } from '@appsemble/utils';
2
+ import { createCountResources, createCreateResource, createGetResourceById, createQueryResources, } from './resources.js';
3
+ import { getRemapperContext } from '../../app.js';
4
+ import { getResourceDefinition } from '../../resource.js';
5
+ let mockGetApp;
6
+ let mockGetAppResources;
7
+ let mockGetAppResource;
8
+ let mockVerifyResourceActionPermission;
9
+ let mockParseQuery;
10
+ let mockGetAppUrl;
11
+ let mockGetAppMessages;
12
+ let mockCreateAppResourcesWithAssets;
13
+ let mockCtx;
14
+ let mockCtxIs;
15
+ describe('createQueryResources', () => {
16
+ beforeEach(() => {
17
+ mockGetApp = vi.fn();
18
+ mockGetAppResources = vi.fn();
19
+ mockVerifyResourceActionPermission = vi.fn();
20
+ mockParseQuery = vi.fn();
21
+ mockGetAppUrl = vi.fn();
22
+ mockGetAppMessages = vi.fn();
23
+ mockCtx = {
24
+ pathParams: { appId: 1, resourceType: 'mockResourceType' },
25
+ queryParams: { $select: 'field1, field2', $skip: 0, $top: 10 },
26
+ user: { id: 'mockUserId', name: 'John Doe', primaryEmail: 'john@example.com' },
27
+ };
28
+ });
29
+ it('should fetch app and resources with correct parameters', async () => {
30
+ const mockApp = {
31
+ id: 1,
32
+ definition: {
33
+ resources: {
34
+ mockResourceType: { id: 'id', schema: {} },
35
+ },
36
+ },
37
+ };
38
+ const mockResources = [{ id: 1 }, { id: 2 }];
39
+ const mockParsedQuery = {
40
+ order: [
41
+ ['mockField1', 'mockOrderAsc'],
42
+ ['mockField2', 'mockOrderDesc'],
43
+ ],
44
+ where: { mockField: 'mockValue' },
45
+ };
46
+ mockGetApp.mockResolvedValue(mockApp);
47
+ mockGetAppResources.mockResolvedValue(mockResources);
48
+ mockParseQuery.mockReturnValue(mockParsedQuery);
49
+ const middleware = createQueryResources({
50
+ getApp: mockGetApp,
51
+ getAppResources: mockGetAppResources,
52
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
53
+ parseQuery: mockParseQuery,
54
+ });
55
+ await middleware(mockCtx, vi.fn());
56
+ expect(mockGetApp).toHaveBeenCalledWith(expect.objectContaining({
57
+ context: expect.objectContaining({
58
+ pathParams: expect.objectContaining({ appId: 1 }),
59
+ }),
60
+ query: expect.objectContaining({ where: { id: 1 } }),
61
+ }));
62
+ expect(mockGetAppResources).toHaveBeenCalledWith(expect.objectContaining({
63
+ app: {
64
+ definition: {
65
+ resources: {
66
+ mockResourceType: {
67
+ id: 'id',
68
+ schema: {},
69
+ },
70
+ },
71
+ },
72
+ id: 1,
73
+ },
74
+ context: expect.objectContaining({
75
+ pathParams: expect.objectContaining({
76
+ appId: 1,
77
+ resourceType: 'mockResourceType',
78
+ }),
79
+ queryParams: expect.objectContaining({
80
+ $select: 'field1, field2',
81
+ $skip: 0,
82
+ $top: 10,
83
+ }),
84
+ user: expect.objectContaining({
85
+ id: 'mockUserId',
86
+ name: 'John Doe',
87
+ primaryEmail: 'john@example.com',
88
+ }),
89
+ }),
90
+ findOptions: expect.objectContaining({
91
+ attributes: ['field1', 'field2'],
92
+ limit: 10,
93
+ offset: 0,
94
+ order: expect.arrayContaining([
95
+ ['mockField1', 'mockOrderAsc'],
96
+ ['mockField2', 'mockOrderDesc'],
97
+ ]),
98
+ where: expect.objectContaining({
99
+ and: expect.arrayContaining([
100
+ expect.objectContaining({ mockField: 'mockValue' }),
101
+ expect.objectContaining({
102
+ AppId: 1,
103
+ expires: expect.objectContaining({
104
+ or: expect.arrayContaining([{ gt: expect.any(Date) }, null]),
105
+ }),
106
+ type: 'mockResourceType',
107
+ }),
108
+ ]),
109
+ }),
110
+ }),
111
+ type: 'mockResourceType',
112
+ }));
113
+ });
114
+ it('should set the response body to resources when no view is specified', async () => {
115
+ const mockApp = {
116
+ id: 1,
117
+ definition: {
118
+ resources: {
119
+ mockResourceType: { id: 'id', schema: {} },
120
+ },
121
+ },
122
+ };
123
+ const mockResources = [{ id: 1 }, { id: 2 }];
124
+ const mockParsedQuery = {
125
+ order: [
126
+ ['mockField1', 'mockOrderAsc'],
127
+ ['mockField2', 'mockOrderDesc'],
128
+ ],
129
+ where: { mockField: 'mockValue' },
130
+ };
131
+ mockGetApp.mockResolvedValue(mockApp);
132
+ mockGetAppResources.mockResolvedValue(mockResources);
133
+ mockParseQuery.mockReturnValue(mockParsedQuery);
134
+ const middleware = createQueryResources({
135
+ getApp: mockGetApp,
136
+ getAppResources: mockGetAppResources,
137
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
138
+ parseQuery: mockParseQuery,
139
+ });
140
+ await middleware(mockCtx, vi.fn());
141
+ expect(mockCtx.body).toStrictEqual(mockResources);
142
+ });
143
+ it('should set the response body to remapped resources when view is specified', async () => {
144
+ const mockApp = {
145
+ id: 1,
146
+ definition: {
147
+ resources: {
148
+ mockResourceType: { id: 'id', schema: {}, views: { view: {} } },
149
+ },
150
+ },
151
+ };
152
+ const mockResources = [{ id: 1 }, { id: 2 }];
153
+ const mockParsedQuery = {
154
+ order: [
155
+ ['mockField1', 'mockOrderAsc'],
156
+ ['mockField2', 'mockOrderDesc'],
157
+ ],
158
+ where: { mockField: 'mockValue' },
159
+ };
160
+ const mockAppUrl = new URL('https://localhost');
161
+ const mockAppMessages = [{ language: 'eng', messages: {} }];
162
+ mockGetApp.mockResolvedValue(mockApp);
163
+ mockGetAppResources.mockResolvedValue(mockResources);
164
+ mockParseQuery.mockReturnValue(mockParsedQuery);
165
+ mockGetAppUrl.mockResolvedValue(mockAppUrl);
166
+ mockGetAppMessages.mockResolvedValue(mockAppMessages);
167
+ mockCtx.queryParams.view = 'view';
168
+ const options = {
169
+ getApp: mockGetApp,
170
+ getAppResources: mockGetAppResources,
171
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
172
+ parseQuery: mockParseQuery,
173
+ getAppUrl: mockGetAppUrl,
174
+ getAppMessages: mockGetAppMessages,
175
+ };
176
+ const resourceDefinition = getResourceDefinition(mockApp, 'mockResourceType', 'view');
177
+ const remapperContext = await getRemapperContext(mockApp, mockApp.definition.defaultLanguage || defaultLocale, null, options, mockCtx);
178
+ const remappedResources = mockResources.map((resource) => remap(resourceDefinition.views.view.remap, resource, remapperContext));
179
+ const middleware = createQueryResources(options);
180
+ await middleware(mockCtx, vi.fn());
181
+ expect(mockCtx.body).toStrictEqual(remappedResources);
182
+ });
183
+ });
184
+ describe('createCountResources', () => {
185
+ beforeEach(() => {
186
+ mockGetApp = vi.fn();
187
+ mockGetAppResources = vi.fn();
188
+ mockVerifyResourceActionPermission = vi.fn();
189
+ mockParseQuery = vi.fn();
190
+ mockCtx = {
191
+ pathParams: { appId: 1, resourceType: 'mockResourceType' },
192
+ queryParams: {},
193
+ user: { id: 'mockUserId', name: 'John Doe', primaryEmail: 'john@example.com' },
194
+ };
195
+ });
196
+ it('should fetch app and resources with correct parameters', async () => {
197
+ const mockApp = {
198
+ id: 1,
199
+ definition: {
200
+ resources: {
201
+ mockResourceType: { id: 'id', schema: {} },
202
+ },
203
+ },
204
+ };
205
+ const mockResources = [{ id: 1 }, { id: 2 }];
206
+ const mockParsedQuery = {
207
+ order: [
208
+ ['mockField1', 'mockOrderAsc'],
209
+ ['mockField2', 'mockOrderDesc'],
210
+ ],
211
+ where: { mockField: 'mockValue' },
212
+ };
213
+ mockGetApp.mockResolvedValue(mockApp);
214
+ mockGetAppResources.mockResolvedValue(mockResources);
215
+ mockParseQuery.mockReturnValue(mockParsedQuery);
216
+ const middleware = createCountResources({
217
+ getApp: mockGetApp,
218
+ getAppResources: mockGetAppResources,
219
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
220
+ parseQuery: mockParseQuery,
221
+ });
222
+ await middleware(mockCtx, vi.fn());
223
+ expect(mockGetApp).toHaveBeenCalledWith(expect.objectContaining({
224
+ context: expect.objectContaining({
225
+ pathParams: expect.objectContaining({ appId: 1 }),
226
+ }),
227
+ query: expect.objectContaining({ where: { id: 1 } }),
228
+ }));
229
+ expect(mockGetAppResources).toHaveBeenCalledWith(expect.objectContaining({
230
+ app: {
231
+ definition: {
232
+ resources: {
233
+ mockResourceType: {
234
+ id: 'id',
235
+ schema: {},
236
+ },
237
+ },
238
+ },
239
+ id: 1,
240
+ },
241
+ context: expect.objectContaining({
242
+ pathParams: expect.objectContaining({
243
+ appId: 1,
244
+ resourceType: 'mockResourceType',
245
+ }),
246
+ user: expect.objectContaining({
247
+ id: 'mockUserId',
248
+ name: 'John Doe',
249
+ primaryEmail: 'john@example.com',
250
+ }),
251
+ }),
252
+ findOptions: expect.objectContaining({
253
+ where: expect.objectContaining({
254
+ and: expect.arrayContaining([
255
+ expect.objectContaining({ mockField: 'mockValue' }),
256
+ expect.objectContaining({
257
+ AppId: 1,
258
+ expires: expect.objectContaining({
259
+ or: expect.arrayContaining([{ gt: expect.any(Date) }, null]),
260
+ }),
261
+ type: 'mockResourceType',
262
+ }),
263
+ ]),
264
+ }),
265
+ }),
266
+ type: 'mockResourceType',
267
+ }));
268
+ });
269
+ it('should set the response body to resources count', async () => {
270
+ const mockApp = {
271
+ id: 1,
272
+ definition: {
273
+ resources: {
274
+ mockResourceType: { id: 'id', schema: {} },
275
+ },
276
+ },
277
+ };
278
+ const mockResources = [{ id: 1 }, { id: 2 }];
279
+ const mockParsedQuery = {
280
+ order: [
281
+ ['mockField1', 'mockOrderAsc'],
282
+ ['mockField2', 'mockOrderDesc'],
283
+ ],
284
+ where: { mockField: 'mockValue' },
285
+ };
286
+ mockGetApp.mockResolvedValue(mockApp);
287
+ mockGetAppResources.mockResolvedValue(mockResources);
288
+ mockParseQuery.mockReturnValue(mockParsedQuery);
289
+ const middleware = createCountResources({
290
+ getApp: mockGetApp,
291
+ getAppResources: mockGetAppResources,
292
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
293
+ parseQuery: mockParseQuery,
294
+ });
295
+ await middleware(mockCtx, vi.fn());
296
+ expect(mockCtx.body).toStrictEqual(mockResources.length);
297
+ });
298
+ });
299
+ describe('createGetResourceById', () => {
300
+ beforeEach(() => {
301
+ mockGetApp = vi.fn();
302
+ mockGetAppResource = vi.fn();
303
+ mockVerifyResourceActionPermission = vi.fn();
304
+ mockGetAppUrl = vi.fn();
305
+ mockGetAppMessages = vi.fn();
306
+ mockCtx = {
307
+ pathParams: { appId: 1, resourceId: 1, resourceType: 'mockResourceType' },
308
+ user: { id: 'mockUserId', name: 'John Doe', primaryEmail: 'john@example.com' },
309
+ };
310
+ });
311
+ it('should fetch app and resource with correct parameters', async () => {
312
+ const mockApp = {
313
+ id: 1,
314
+ definition: {
315
+ resources: {
316
+ mockResourceType: { id: 'id', schema: {} },
317
+ },
318
+ },
319
+ };
320
+ const mockResource = { id: 1 };
321
+ mockGetApp.mockResolvedValue(mockApp);
322
+ mockGetAppResource.mockResolvedValue(mockResource);
323
+ const middleware = createGetResourceById({
324
+ getApp: mockGetApp,
325
+ getAppResource: mockGetAppResource,
326
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
327
+ });
328
+ await middleware(mockCtx, vi.fn());
329
+ expect(mockGetApp).toHaveBeenCalledWith(expect.objectContaining({
330
+ context: expect.objectContaining({
331
+ pathParams: expect.objectContaining({ appId: 1 }),
332
+ }),
333
+ query: expect.objectContaining({ where: { id: 1 } }),
334
+ }));
335
+ expect(mockGetAppResource).toHaveBeenCalledWith(expect.objectContaining({
336
+ app: {
337
+ definition: {
338
+ resources: {
339
+ mockResourceType: {
340
+ id: 'id',
341
+ schema: {},
342
+ },
343
+ },
344
+ },
345
+ id: 1,
346
+ },
347
+ id: 1,
348
+ type: 'mockResourceType',
349
+ context: expect.objectContaining({
350
+ pathParams: expect.objectContaining({
351
+ appId: 1,
352
+ resourceType: 'mockResourceType',
353
+ }),
354
+ user: expect.objectContaining({
355
+ id: 'mockUserId',
356
+ name: 'John Doe',
357
+ primaryEmail: 'john@example.com',
358
+ }),
359
+ }),
360
+ findOptions: expect.objectContaining({
361
+ where: expect.objectContaining({
362
+ id: 1,
363
+ type: 'mockResourceType',
364
+ AppId: 1,
365
+ expires: expect.objectContaining({
366
+ or: expect.arrayContaining([{ gt: expect.any(Date) }, null]),
367
+ }),
368
+ }),
369
+ }),
370
+ }));
371
+ });
372
+ it('should set the response body to resource when no view is specified', async () => {
373
+ const mockApp = {
374
+ id: 1,
375
+ definition: {
376
+ resources: {
377
+ mockResourceType: { id: 'id', schema: {} },
378
+ },
379
+ },
380
+ };
381
+ const mockResource = { id: 1 };
382
+ mockGetApp.mockResolvedValue(mockApp);
383
+ mockGetAppResource.mockResolvedValue(mockResource);
384
+ const middleware = createGetResourceById({
385
+ getApp: mockGetApp,
386
+ getAppResource: mockGetAppResource,
387
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
388
+ });
389
+ await middleware(mockCtx, vi.fn());
390
+ expect(mockCtx.body).toStrictEqual(mockResource);
391
+ });
392
+ it('should set the response body to remapped resource when view is specified', async () => {
393
+ const mockApp = {
394
+ id: 1,
395
+ definition: {
396
+ resources: {
397
+ mockResourceType: { id: 'id', schema: {}, views: { view: {} } },
398
+ },
399
+ },
400
+ };
401
+ const mockResource = { id: 1 };
402
+ const mockAppUrl = new URL('https://localhost');
403
+ const mockAppMessages = [{ language: 'eng', messages: {} }];
404
+ mockGetApp.mockResolvedValue(mockApp);
405
+ mockGetAppResource.mockResolvedValue(mockResource);
406
+ mockGetAppUrl.mockResolvedValue(mockAppUrl);
407
+ mockGetAppMessages.mockResolvedValue(mockAppMessages);
408
+ mockCtx.queryParams = { view: 'view' };
409
+ const options = {
410
+ getApp: mockGetApp,
411
+ getAppResource: mockGetAppResource,
412
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
413
+ getAppUrl: mockGetAppUrl,
414
+ getAppMessages: mockGetAppMessages,
415
+ };
416
+ const resourceDefinition = getResourceDefinition(mockApp, 'mockResourceType', 'view');
417
+ const remapperContext = await getRemapperContext(mockApp, mockApp.definition.defaultLanguage || defaultLocale, null, options, mockCtx);
418
+ const remappedResource = remap(resourceDefinition.views.view.remap, mockResource, remapperContext);
419
+ const middleware = createGetResourceById(options);
420
+ await middleware(mockCtx, vi.fn());
421
+ expect(mockCtx.body).toStrictEqual(remappedResource);
422
+ });
423
+ });
424
+ describe('createCreateResource', () => {
425
+ beforeEach(() => {
426
+ mockGetApp = vi.fn();
427
+ mockVerifyResourceActionPermission = vi.fn();
428
+ mockCreateAppResourcesWithAssets = vi.fn();
429
+ mockCtxIs = vi.fn();
430
+ mockCtx = {
431
+ pathParams: { appId: 1, resourceType: 'mockResourceType' },
432
+ user: { id: 'mockUserId', name: 'John Doe', primaryEmail: 'john@example.com' },
433
+ is: mockCtxIs,
434
+ request: {},
435
+ };
436
+ });
437
+ it('should fetch app and create multiple resources', async () => {
438
+ const mockApp = {
439
+ id: 1,
440
+ definition: {
441
+ resources: {
442
+ mockResourceType: { id: 'id', schema: {} },
443
+ },
444
+ },
445
+ };
446
+ const mockResources = [{ id: 1 }, { id: 2 }];
447
+ mockCtx.request.body = { resource: mockResources };
448
+ mockGetApp.mockResolvedValue(mockApp);
449
+ mockCtxIs.mockReturnValue('multipart/form-data');
450
+ mockCreateAppResourcesWithAssets.mockResolvedValue(mockResources);
451
+ const middleware = createCreateResource({
452
+ getApp: mockGetApp,
453
+ createAppResourcesWithAssets: mockCreateAppResourcesWithAssets,
454
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
455
+ });
456
+ await middleware(mockCtx, vi.fn());
457
+ expect(mockGetApp).toHaveBeenCalledWith(expect.objectContaining({
458
+ context: expect.objectContaining({
459
+ pathParams: expect.objectContaining({ appId: 1 }),
460
+ }),
461
+ query: expect.objectContaining({ where: { id: 1 } }),
462
+ }));
463
+ expect(mockCreateAppResourcesWithAssets).toHaveBeenCalledWith(expect.objectContaining({
464
+ app: expect.objectContaining({
465
+ definition: expect.objectContaining({
466
+ resources: expect.objectContaining({
467
+ mockResourceType: expect.objectContaining({
468
+ id: 'id',
469
+ schema: {},
470
+ }),
471
+ }),
472
+ }),
473
+ id: 1,
474
+ }),
475
+ context: expect.objectContaining({
476
+ request: expect.objectContaining({
477
+ body: {
478
+ resource: mockResources,
479
+ },
480
+ }),
481
+ pathParams: expect.objectContaining({
482
+ appId: 1,
483
+ resourceType: 'mockResourceType',
484
+ }),
485
+ user: expect.objectContaining({
486
+ id: 'mockUserId',
487
+ name: 'John Doe',
488
+ primaryEmail: 'john@example.com',
489
+ }),
490
+ }),
491
+ }));
492
+ expect(mockCtx.body).toStrictEqual(mockResources);
493
+ });
494
+ it('should fetch app and create a single resource', async () => {
495
+ const mockApp = {
496
+ id: 1,
497
+ definition: {
498
+ resources: {
499
+ mockResourceType: { id: 'id', schema: {} },
500
+ },
501
+ },
502
+ };
503
+ const mockResources = [{ id: 1 }];
504
+ mockCtx.request.body = { resource: mockResources[0] };
505
+ mockGetApp.mockResolvedValue(mockApp);
506
+ mockCtxIs.mockReturnValue('multipart/form-data');
507
+ mockCreateAppResourcesWithAssets.mockResolvedValue(mockResources);
508
+ const middleware = createCreateResource({
509
+ getApp: mockGetApp,
510
+ createAppResourcesWithAssets: mockCreateAppResourcesWithAssets,
511
+ verifyResourceActionPermission: mockVerifyResourceActionPermission,
512
+ });
513
+ await middleware(mockCtx, vi.fn());
514
+ expect(mockGetApp).toHaveBeenCalledWith(expect.objectContaining({
515
+ context: expect.objectContaining({
516
+ pathParams: expect.objectContaining({ appId: 1 }),
517
+ }),
518
+ query: expect.objectContaining({ where: { id: 1 } }),
519
+ }));
520
+ expect(mockCreateAppResourcesWithAssets).toHaveBeenCalledWith(expect.objectContaining({
521
+ app: expect.objectContaining({
522
+ definition: expect.objectContaining({
523
+ resources: expect.objectContaining({
524
+ mockResourceType: expect.objectContaining({
525
+ id: 'id',
526
+ schema: {},
527
+ }),
528
+ }),
529
+ }),
530
+ id: 1,
531
+ }),
532
+ context: expect.objectContaining({
533
+ request: expect.objectContaining({
534
+ body: {
535
+ resource: mockResources[0],
536
+ },
537
+ }),
538
+ pathParams: expect.objectContaining({
539
+ appId: 1,
540
+ resourceType: 'mockResourceType',
541
+ }),
542
+ user: expect.objectContaining({
543
+ id: 'mockUserId',
544
+ name: 'John Doe',
545
+ primaryEmail: 'john@example.com',
546
+ }),
547
+ }),
548
+ }));
549
+ expect(mockCtx.body).toStrictEqual(mockResources[0]);
550
+ });
551
+ });
552
+ //# sourceMappingURL=resources.test.js.map
@@ -0,0 +1,3 @@
1
+ import { type Middleware } from 'koa';
2
+ import { type Options } from '../types.js';
3
+ export declare function createGetTeams({ getApp, getAppTeams }: Options): Middleware;
@@ -0,0 +1,12 @@
1
+ import { notFound } from '@hapi/boom';
2
+ export function createGetTeams({ getApp, getAppTeams }) {
3
+ return async (ctx) => {
4
+ const { pathParams: { appId }, user, } = ctx;
5
+ const app = await getApp({ context: ctx, query: { where: { id: appId } } });
6
+ if (!app) {
7
+ throw notFound('App not found');
8
+ }
9
+ ctx.body = await getAppTeams({ context: ctx, app, user });
10
+ };
11
+ }
12
+ //# sourceMappingURL=teams.js.map
@@ -0,0 +1,3 @@
1
+ import { type Options } from '@appsemble/node-utils';
2
+ import { type Middleware } from 'koa';
3
+ export declare function createBlockAssetHandler({ getBlockAsset }: Options): Middleware;
@@ -0,0 +1,13 @@
1
+ import { notFound } from '@hapi/boom';
2
+ export function createBlockAssetHandler({ getBlockAsset }) {
3
+ return async (ctx) => {
4
+ const { params: { filename, name, version }, } = ctx;
5
+ const blockAsset = await getBlockAsset({ filename, name, version, context: ctx });
6
+ if (!blockAsset) {
7
+ throw notFound('Block asset not found');
8
+ }
9
+ ctx.body = blockAsset.content;
10
+ ctx.type = blockAsset.mime;
11
+ };
12
+ }
13
+ //# sourceMappingURL=blockAssetHandler.js.map
@@ -0,0 +1,3 @@
1
+ import { type Options } from '@appsemble/node-utils';
2
+ import { type Middleware } from 'koa';
3
+ export declare function createBlockCssHandler({ getApp, getAppBlockStyles }: Options): Middleware;
@@ -0,0 +1,15 @@
1
+ import { notFound } from '@hapi/boom';
2
+ export function createBlockCssHandler({ getApp, getAppBlockStyles }) {
3
+ return async (ctx) => {
4
+ const { params: { name }, } = ctx;
5
+ const app = await getApp({ context: ctx });
6
+ if (!app) {
7
+ throw notFound('App not found');
8
+ }
9
+ const appBlockStyles = await getAppBlockStyles({ app, name, context: ctx });
10
+ const [style] = appBlockStyles;
11
+ ctx.body = style ? style.style : '';
12
+ ctx.type = 'css';
13
+ };
14
+ }
15
+ //# sourceMappingURL=blockCssHandler.js.map
@@ -0,0 +1,3 @@
1
+ import { type Options } from '@appsemble/node-utils';
2
+ import { type Middleware } from 'koa';
3
+ export declare function createBulmaHandler({ createTheme, getTheme }: Options): Middleware;