spine-framework 0.3.113 → 0.3.114
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/.framework/functions/admin-data.ts +121 -77
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// ─── CHUNK_START: ADMIN_DATA_OVERVIEW ──────────────────────────────────────────────
|
|
1
2
|
/**
|
|
2
3
|
* @module admin-data
|
|
3
4
|
* @audience both
|
|
@@ -46,8 +47,38 @@ import { sanitizeRecordData } from './_shared/permissions'
|
|
|
46
47
|
import { adminDb } from './_shared/db'
|
|
47
48
|
import { resolveTypeId } from './_shared/resolve-ids'
|
|
48
49
|
import { fireCreateTriggers, fireUpdateTriggers, fireDeleteTriggers } from './_shared/trigger-engine'
|
|
50
|
+
// ─── CHUNK_END: ADMIN_DATA_OVERVIEW ──────────────────────────────────────────────
|
|
49
51
|
|
|
50
|
-
// ───
|
|
52
|
+
// ─── CHUNK_START: ADMIN_DATA_MODULE_HEADER ──────────────────────────────────────────────
|
|
53
|
+
/**
|
|
54
|
+
* @chunk-id ADMIN_DATA_MODULE_HEADER_1_0_0
|
|
55
|
+
* @version 1.0.0
|
|
56
|
+
* @hash TBD
|
|
57
|
+
* @macro Module Header
|
|
58
|
+
* @micro Module-level documentation with routing table and invariants
|
|
59
|
+
* @inputs none
|
|
60
|
+
* @outputs none
|
|
61
|
+
* @depends-on [none]
|
|
62
|
+
* @depended-by [all chunks]
|
|
63
|
+
* @side-effects [none]
|
|
64
|
+
* @tags admin, module, routing, invariants
|
|
65
|
+
*/
|
|
66
|
+
// ─── CHUNK_END: ADMIN_DATA_MODULE_HEADER ────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
// ─── CHUNK_START: ADMIN_DATA_IMPORTS_AND_CONSTANTS ──────────────────────────────────────────────
|
|
69
|
+
/**
|
|
70
|
+
* @chunk-id ADMIN_DATA_IMPORTS_AND_CONSTANTS_1_0_0
|
|
71
|
+
* @version 1.0.0
|
|
72
|
+
* @hash TBD
|
|
73
|
+
* @macro Imports and Constants
|
|
74
|
+
* @micro Module imports and constant definitions
|
|
75
|
+
* @inputs none
|
|
76
|
+
* @outputs none
|
|
77
|
+
* @depends-on [none]
|
|
78
|
+
* @depended-by [all handlers]
|
|
79
|
+
* @side-effects [none]
|
|
80
|
+
* @tags admin, imports, constants
|
|
81
|
+
*/
|
|
51
82
|
|
|
52
83
|
const PERMISSIONS_ALL = {
|
|
53
84
|
record_permissions: { all: ['create', 'read', 'update', 'delete'] },
|
|
@@ -70,8 +101,23 @@ const ENTITY_TO_KIND: Record<string, string> = {
|
|
|
70
101
|
watchers: 'watcher',
|
|
71
102
|
item_progress: 'item_progress'
|
|
72
103
|
}
|
|
104
|
+
// ─── CHUNK_END: ADMIN_DATA_IMPORTS_AND_CONSTANTS ────────────────────────────────────────────────
|
|
73
105
|
|
|
74
|
-
// ───
|
|
106
|
+
// ─── CHUNK_START: ADMIN_DATA_HANDLERS_SECTION ──────────────────────────────────────────────
|
|
107
|
+
/**
|
|
108
|
+
* @chunk-id ADMIN_DATA_HANDLERS_SECTION_1_0_0
|
|
109
|
+
* @version 1.0.0
|
|
110
|
+
* @hash TBD
|
|
111
|
+
* @macro Handlers Section Header
|
|
112
|
+
* @micro Section marker for CRUD handler functions
|
|
113
|
+
* @inputs none
|
|
114
|
+
* @outputs none
|
|
115
|
+
* @depends-on [none]
|
|
116
|
+
* @depended-by [none]
|
|
117
|
+
* @side-effects [none]
|
|
118
|
+
* @tags admin, section, handlers
|
|
119
|
+
*/
|
|
120
|
+
// ─── CHUNK_END: ADMIN_DATA_HANDLERS_SECTION ────────────────────────────────────────────────
|
|
75
121
|
|
|
76
122
|
// ─── CHUNK_START: ADMIN_DATA_LIST ──────────────────────────────────────────────
|
|
77
123
|
/**
|
|
@@ -230,32 +276,20 @@ export const get = createHandler(async (ctx, _body) => {
|
|
|
230
276
|
})
|
|
231
277
|
// ─── CHUNK_END: ADMIN_DATA_GET ────────────────────────────────────────────────
|
|
232
278
|
|
|
279
|
+
// ─── CHUNK_START: ADMIN_DATA_CREATE ──────────────────────────────────────────────
|
|
233
280
|
/**
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
* @
|
|
244
|
-
* @
|
|
245
|
-
* @
|
|
246
|
-
* @throws Error('type_id not found') — if type UUID doesn't exist
|
|
247
|
-
* @throws Error('type_id references an inactive type')
|
|
248
|
-
* @throws PostgREST error on RLS INSERT denial
|
|
249
|
-
* @inputSpec type_id: string — valid UUID of active type record
|
|
250
|
-
* @inputSpec body fields: Record<string, any> — record field values
|
|
251
|
-
* @outputSpec sanitized created record
|
|
252
|
-
* @sideEffects DB write: entity table (INSERT)
|
|
253
|
-
* @sideEffects DB read: types table (type resolution)
|
|
254
|
-
* @sideEffects fire-and-forget: fireCreateTriggers
|
|
255
|
-
* @calledBy handler (POST)
|
|
256
|
-
* @calls sanitizeRecordData, adminDb (type lookup), fireCreateTriggers
|
|
257
|
-
* @testUnit tests/unit/admin-data.test.ts — 'create'
|
|
258
|
-
* @testIntegration tests/integration/admin-data.test.ts — 'create'
|
|
281
|
+
* @chunk-id ADMIN_DATA_CREATE_1_0_0
|
|
282
|
+
* @version 1.0.0
|
|
283
|
+
* @hash TBD
|
|
284
|
+
* @macro Entity Create Handler
|
|
285
|
+
* @micro Creates a new record for an entity with type resolution and triggers
|
|
286
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
287
|
+
* @inputs body: any — Request body with entity, type_id/type_slug, and record fields
|
|
288
|
+
* @outputs Sanitized created record
|
|
289
|
+
* @depends-on [createHandler, sanitizeRecordData, adminDb, resolveTypeId, fireCreateTriggers]
|
|
290
|
+
* @depended-by [Netlify function routing]
|
|
291
|
+
* @side-effects [DB write, type lookup, async trigger fire]
|
|
292
|
+
* @tags admin, crud, create, type-resolution
|
|
259
293
|
*/
|
|
260
294
|
export const create = createHandler(async (ctx, body) => {
|
|
261
295
|
const entity = body?.entity || ctx.query?.entity
|
|
@@ -361,31 +395,27 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
361
395
|
|
|
362
396
|
return await sanitizeRecordData(ctx, data, entity)
|
|
363
397
|
})
|
|
398
|
+
// ─── CHUNK_END: ADMIN_DATA_CREATE ────────────────────────────────────────────────
|
|
364
399
|
|
|
400
|
+
// ─── CHUNK_START: ADMIN_DATA_UPDATE ──────────────────────────────────────────────
|
|
365
401
|
/**
|
|
366
|
-
*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
* @
|
|
373
|
-
* @
|
|
374
|
-
* @
|
|
375
|
-
* @
|
|
376
|
-
* @
|
|
377
|
-
* @
|
|
378
|
-
* @outputSpec sanitized updated record
|
|
379
|
-
* @sideEffects DB write: entity table (UPDATE)
|
|
380
|
-
* @sideEffects fire-and-forget: fireUpdateTriggers
|
|
381
|
-
* @calledBy handler (PATCH)
|
|
382
|
-
* @calls sanitizeRecordData, fireUpdateTriggers
|
|
383
|
-
* @testUnit tests/unit/admin-data.test.ts — 'update'
|
|
402
|
+
* @chunk-id ADMIN_DATA_UPDATE_1_0_0
|
|
403
|
+
* @version 1.0.0
|
|
404
|
+
* @hash TBD
|
|
405
|
+
* @macro Entity Update Handler
|
|
406
|
+
* @micro Updates an existing record by ID with audit fields and triggers
|
|
407
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
408
|
+
* @inputs body: any — Request body with partial record fields to update
|
|
409
|
+
* @outputs Sanitized updated record
|
|
410
|
+
* @depends-on [createHandler, sanitizeRecordData, fireUpdateTriggers]
|
|
411
|
+
* @depended-by [Netlify function routing]
|
|
412
|
+
* @side-effects [DB write, async trigger fire]
|
|
413
|
+
* @tags admin, crud, update
|
|
384
414
|
*/
|
|
385
415
|
export const update = createHandler(async (ctx, body) => {
|
|
386
416
|
const { entity, id } = ctx.query || {}
|
|
387
417
|
// Strip server-only fields — client must never override these on update
|
|
388
|
-
const { design_schema: _ds, validation_schema: _vs, account_id: _ai, type_id: _ti, ...recordData } = body || {}
|
|
418
|
+
const { design_schema: _ds, validation_schema: _vs, account_id: _ai, type_id: _ti, type_slug: _ts, ...recordData } = body || {}
|
|
389
419
|
|
|
390
420
|
if (!entity || !VALID_ENTITIES.includes(entity)) {
|
|
391
421
|
throw new Error('Valid entity parameter is required')
|
|
@@ -417,31 +447,22 @@ export const update = createHandler(async (ctx, body) => {
|
|
|
417
447
|
|
|
418
448
|
return await sanitizeRecordData(ctx, data, entity)
|
|
419
449
|
})
|
|
450
|
+
// ─── CHUNK_END: ADMIN_DATA_UPDATE ────────────────────────────────────────────────
|
|
420
451
|
|
|
452
|
+
// ─── CHUNK_START: ADMIN_DATA_REMOVE ──────────────────────────────────────────────
|
|
421
453
|
/**
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
* @
|
|
434
|
-
* @throws Error('Valid entity parameter is required')
|
|
435
|
-
* @throws Error('ID is required for delete')
|
|
436
|
-
* @throws PostgREST error on RLS DELETE denial
|
|
437
|
-
* @inputSpec id: string — valid UUID
|
|
438
|
-
* @inputSpec soft: 'true' | 'false'
|
|
439
|
-
* @outputSpec { deleted: boolean, soft: boolean, data?: sanitizedRecord }
|
|
440
|
-
* @sideEffects DB write: UPDATE is_active=false (soft) or DELETE (hard)
|
|
441
|
-
* @sideEffects fire-and-forget: fireDeleteTriggers
|
|
442
|
-
* @calledBy handler (DELETE)
|
|
443
|
-
* @calls sanitizeRecordData, entitySupportsSoftDelete, fireDeleteTriggers
|
|
444
|
-
* @testUnit tests/unit/admin-data.test.ts — 'remove'
|
|
454
|
+
* @chunk-id ADMIN_DATA_REMOVE_1_0_0
|
|
455
|
+
* @version 1.0.0
|
|
456
|
+
* @hash TBD
|
|
457
|
+
* @macro Entity Delete Handler
|
|
458
|
+
* @micro Deletes a record by ID with soft delete support and triggers
|
|
459
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
460
|
+
* @inputs _body: any — Request body (unused for DELETE)
|
|
461
|
+
* @outputs { deleted: boolean, soft: boolean, data?: sanitizedRecord }
|
|
462
|
+
* @depends-on [createHandler, sanitizeRecordData, entitySupportsSoftDelete, fireDeleteTriggers]
|
|
463
|
+
* @depended-by [Netlify function routing]
|
|
464
|
+
* @side-effects [DB write, async trigger fire]
|
|
465
|
+
* @tags admin, crud, delete, soft-delete
|
|
445
466
|
*/
|
|
446
467
|
export const remove = createHandler(async (ctx, _body) => {
|
|
447
468
|
const { entity, id, soft = 'true' } = ctx.query || {}
|
|
@@ -482,15 +503,24 @@ export const remove = createHandler(async (ctx, _body) => {
|
|
|
482
503
|
return { deleted: true, soft: false }
|
|
483
504
|
}
|
|
484
505
|
})
|
|
506
|
+
// ─── CHUNK_END: ADMIN_DATA_REMOVE ────────────────────────────────────────────────
|
|
485
507
|
|
|
486
|
-
// ───
|
|
487
|
-
|
|
508
|
+
// ─── CHUNK_START: ADMIN_DATA_HELPERS_SECTION ──────────────────────────────────────────────
|
|
488
509
|
/**
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
* @
|
|
510
|
+
* @chunk-id ADMIN_DATA_HELPERS_SECTION_1_0_0
|
|
511
|
+
* @version 1.0.0
|
|
512
|
+
* @hash TBD
|
|
513
|
+
* @macro Helpers Section Header
|
|
514
|
+
* @micro Section marker for helper functions
|
|
515
|
+
* @inputs none
|
|
516
|
+
* @outputs none
|
|
517
|
+
* @depends-on [none]
|
|
518
|
+
* @depended-by [none]
|
|
519
|
+
* @side-effects [none]
|
|
520
|
+
* @tags admin, section, helpers
|
|
493
521
|
*/
|
|
522
|
+
// ─── CHUNK_END: ADMIN_DATA_HELPERS_SECTION ────────────────────────────────────────────────
|
|
523
|
+
|
|
494
524
|
// ─── CHUNK_START: ADMIN_DATA_GET_SEARCH_FIELD ──────────────────────────────────────────────
|
|
495
525
|
/**
|
|
496
526
|
* @chunk-id ADMIN_DATA_GET_SEARCH_FIELD_1_0_0
|
|
@@ -573,7 +603,21 @@ export const stats = createHandler(async (ctx, _body) => {
|
|
|
573
603
|
})
|
|
574
604
|
// ─── CHUNK_END: ADMIN_DATA_STATS ────────────────────────────────────────────────
|
|
575
605
|
|
|
576
|
-
// ───
|
|
606
|
+
// ─── CHUNK_START: ADMIN_DATA_MAIN_HANDLER_SECTION ──────────────────────────────────────────────
|
|
607
|
+
/**
|
|
608
|
+
* @chunk-id ADMIN_DATA_MAIN_HANDLER_SECTION_1_0_0
|
|
609
|
+
* @version 1.0.0
|
|
610
|
+
* @hash TBD
|
|
611
|
+
* @macro Main Handler Section Header
|
|
612
|
+
* @micro Section marker for the main router handler
|
|
613
|
+
* @inputs none
|
|
614
|
+
* @outputs none
|
|
615
|
+
* @depends-on [none]
|
|
616
|
+
* @depended-by [none]
|
|
617
|
+
* @side-effects [none]
|
|
618
|
+
* @tags admin, section, main-handler
|
|
619
|
+
*/
|
|
620
|
+
// ─── CHUNK_END: ADMIN_DATA_MAIN_HANDLER_SECTION ────────────────────────────────────────────────
|
|
577
621
|
|
|
578
622
|
// ─── CHUNK_START: ADMIN_DATA_HANDLER ──────────────────────────────────────────────
|
|
579
623
|
/**
|
|
@@ -626,4 +670,4 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
626
670
|
|
|
627
671
|
throw new Error('Invalid action or method')
|
|
628
672
|
})
|
|
629
|
-
// ─── CHUNK_END: ADMIN_DATA_HANDLER ────────────────────────────────────────────────
|
|
673
|
+
// ─── CHUNK_END: ADMIN_DATA_HANDLER ────────────────────────────────────────────────
|