@opengis/fcore 0.0.27 → 0.0.28

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 (107) hide show
  1. package/LICENSE +3 -3
  2. package/README.md +71 -71
  3. package/dist/config.js +1 -1
  4. package/dist/context.js +1 -1
  5. package/dist/errors.js +1 -1
  6. package/dist/fastify.js +1 -1
  7. package/dist/fcore.js +1 -1
  8. package/dist/migrations/cli.js +1 -1
  9. package/dist/migrations/runner.js +1 -1
  10. package/dist/modules/auth/adduser-cli.js +1 -1
  11. package/dist/modules/auth/passwd-cli.js +1 -1
  12. package/dist/modules/auth/permission-cli.js +1 -1
  13. package/dist/modules/auth/route.js +1 -1
  14. package/dist/modules/auth/schema.js +1 -1
  15. package/dist/modules/auth/services/change-password.js +1 -1
  16. package/dist/modules/auth/services/get-current-user.js +1 -1
  17. package/dist/modules/auth/services/registration.js +1 -1
  18. package/dist/modules/auth/services/verify-two-factor.js +1 -1
  19. package/dist/modules/file/mime.js +1 -1
  20. package/dist/modules/file/route.js +1 -1
  21. package/dist/modules/file/schema.js +1 -1
  22. package/dist/modules/file/services/get-file.js +1 -1
  23. package/dist/modules/file/services/resize-file.js +1 -1
  24. package/dist/modules/file/services/upload-file.js +1 -1
  25. package/dist/modules/resource/route.js +1 -1
  26. package/dist/modules/resource/schema.js +1 -1
  27. package/dist/modules/resource/services/add-note.js +1 -1
  28. package/dist/modules/resource/services/add-resource-file.js +1 -1
  29. package/dist/modules/resource/services/create-resource-relation.js +1 -1
  30. package/dist/modules/resource/services/create-resource.js +1 -1
  31. package/dist/modules/resource/services/delete-resource-relation.js +1 -1
  32. package/dist/modules/resource/services/delete-resource.js +1 -1
  33. package/dist/modules/resource/services/export-resource.js +1 -1
  34. package/dist/modules/resource/services/generate-resource-code.js +1 -1
  35. package/dist/modules/resource/services/get-resource-schema.js +1 -1
  36. package/dist/modules/resource/services/get-resource.js +1 -1
  37. package/dist/modules/resource/services/list-resource-as-user.js +1 -1
  38. package/dist/modules/resource/services/list-resource-list.js +1 -1
  39. package/dist/modules/resource/services/list-resource-relation.js +1 -1
  40. package/dist/modules/resource/services/list-resources.js +1 -1
  41. package/dist/modules/resource/services/search-resource.js +1 -1
  42. package/dist/modules/resource/services/suggest-resource.js +1 -1
  43. package/dist/modules/resource/services/update-resource-relation.js +1 -1
  44. package/dist/modules/resource/services/update-resource.js +1 -1
  45. package/dist/modules/resource/services/upload-resource-file.js +1 -1
  46. package/dist/modules/system/route.js +1 -1
  47. package/dist/modules/system/schema.js +1 -1
  48. package/dist/modules/system/services/check-system.js +1 -1
  49. package/dist/modules/system/services/get-access.js +1 -1
  50. package/dist/modules/system/services/get-api-list.js +1 -1
  51. package/dist/modules/system/services/get-audit-log.js +1 -1
  52. package/dist/modules/system/services/get-dictionary.js +1 -1
  53. package/dist/modules/system/services/get-resource-access.js +1 -1
  54. package/dist/modules/system/services/get-resource-scopes.js +1 -1
  55. package/dist/modules/system/services/get-system-log.js +1 -1
  56. package/dist/modules/system/services/get-system-settings.js +1 -1
  57. package/dist/modules/system/services/list-dictionaries.js +1 -1
  58. package/dist/modules/system/services/set-access.js +1 -1
  59. package/dist/modules/system/services/set-resource-access.js +1 -1
  60. package/dist/modules/system/services/set-resource-scopes.js +1 -1
  61. package/dist/modules/system/services/update-dictionary.js +1 -1
  62. package/dist/modules/system/services/update-system-settings.js +1 -1
  63. package/dist/modules/utils/require-admin.js +1 -1
  64. package/dist/modules/utils/safe-user.js +1 -1
  65. package/dist/modules/utils/unsupported.js +1 -1
  66. package/dist/plugins/audit/audit.js +1 -1
  67. package/dist/plugins/audit/services/write-audit.js +1 -1
  68. package/dist/plugins/auth/get-user-permissions.js +1 -1
  69. package/dist/plugins/auth/index.js +1 -1
  70. package/dist/plugins/auth/verifyUser.js +1 -1
  71. package/dist/plugins/dictionary.js +1 -1
  72. package/dist/plugins/file.js +1 -1
  73. package/dist/plugins/jwt.js +1 -1
  74. package/dist/plugins/logger/index.js +1 -1
  75. package/dist/plugins/logger/transport.js +1 -1
  76. package/dist/plugins/pg.js +1 -1
  77. package/dist/plugins/redis.js +1 -1
  78. package/dist/plugins/resource/resource.js +1 -1
  79. package/dist/plugins/resource/resource.registry.js +1 -1
  80. package/dist/plugins/resource/services/add-dictionary-lookup-data.js +1 -1
  81. package/dist/plugins/resource/services/add-file-token.js +1 -1
  82. package/dist/plugins/resource/services/add-table-lookup-data.js +1 -1
  83. package/dist/plugins/resource/services/create-relation.d.ts.map +1 -1
  84. package/dist/plugins/resource/services/create-relation.js +1 -1
  85. package/dist/plugins/resource/services/create.js +1 -1
  86. package/dist/plugins/resource/services/delete-relation.d.ts.map +1 -1
  87. package/dist/plugins/resource/services/delete-relation.js +1 -1
  88. package/dist/plugins/resource/services/delete.js +1 -1
  89. package/dist/plugins/resource/services/find-one.js +1 -1
  90. package/dist/plugins/resource/services/find-relation.js +1 -1
  91. package/dist/plugins/resource/services/find.js +1 -1
  92. package/dist/plugins/resource/services/get-table-columns.js +1 -1
  93. package/dist/plugins/resource/services/update-relation.js +1 -1
  94. package/dist/plugins/resource/services/update.js +1 -1
  95. package/dist/plugins/resource/utils/auto-index.js +1 -1
  96. package/dist/plugins/resource/utils/fields.js +1 -1
  97. package/dist/plugins/resource/utils/filters.js +1 -1
  98. package/dist/plugins/resource/utils/permissions.js +1 -1
  99. package/dist/plugins/resource/utils/scope.js +1 -1
  100. package/dist/plugins/resource/utils/sort.js +1 -1
  101. package/dist/plugins/resource/utils/sql.js +1 -1
  102. package/dist/plugins/resource/utils/summary.js +1 -1
  103. package/dist/shared/getIP.js +1 -1
  104. package/migrations/20260903130000_move_notes_files_to_admin.sql +17 -17
  105. package/migrations/20260903140000_settings_nulls_not_distinct.sql +18 -18
  106. package/migrations/20260929120000_allow_user_only_role_scopes.sql +1 -1
  107. package/package.json +92 -92
@@ -1 +1 @@
1
- const i=C;import{fieldColumn,qi}from'./sql.js';import{ValidationError}from'../../../errors.js';import{autoIndex}from'./auto-index.js';const filterOperators=new Set(['eq','ne','gt','gte','lt','lte','in','nin','like','ilike',i(0x17d)]);function C(P,G){P=P-0x17d;const j=m();let Z=j[P];return Z;}export function parseFilterQuery(P){const y=i,G={...isRecord(P['filter'])?P['filter']:{}};for(const [j,Z]of Object['entries'](P)){const q=/^filter\[([^\]]+)\](?:\[([^\]]+)\])?$/[y(0x17e)](j);if(!q)continue;const [,p,X]=q;if(!p)continue;if(!X){G[p]=Z;continue;}if(!filterOperators[y(0x17f)](X))throw new ValidationError('Unsupported\x20filter\x20operator:\x20'+X);const F=isRecord(G[p])?G[p]:{};F[X]=(X==='in'||X===y(0x180))&&typeof Z==='string'?Z['split'](','):Z,G[p]=F;}return Object['keys'](G)['length']?G:undefined;}export function buildIndex(P,G,j){const T=i;for(const [Z,q]of Object['entries'](G??{})){const p=P[T(0x181)][Z];if(!p||p['filter']!==!![]&&p['filterable']!==!![])throw new ValidationError('Field\x20is\x20not\x20filterable:\x20'+Z);j&&autoIndex(P[T(0x182)],fieldColumn(P,Z),indexTypeFor(p['type'],'eq'),j);}}export function buildFilters(P,G,j=0x1){const D=i,Z=[],q=[];for(const [p,X]of Object['entries'](G??{})){const F=P['fields'][p];if(!F||F[D(0x183)]!==!![]&&F[D(0x184)]!==!![])throw new ValidationError('Field\x20is\x20not\x20filterable:\x20'+p);const A=qi(fieldColumn(P,p)),H=isRecord(X)?X:{'eq':X};for(const [b,E]of Object['entries'](H)){if(!filterOperators['has'](b))throw new ValidationError('Unsupported\x20filter\x20operator:\x20'+b);if((b==='like'||b==='ilike')&&F[D(0x185)]!=='string'&&F['type']!=='text')throw new ValidationError('Operator\x20'+b+'\x20requires\x20a\x20text\x20field:\x20'+p);if(b==='null'){Z['push'](A+'\x20IS\x20'+(isTruthy(E)?'':'NOT\x20')+D(0x186));continue;}if(b==='in'||b==='nin'){const o=Array['isArray'](E)?E:[E];if(o[D(0x187)]===0x0){Z[D(0x188)](b==='in'?D(0x189):'TRUE');continue;}q['push'](o),Z[D(0x188)](A+'\x20'+(b==='in'?'=\x20ANY':'<>\x20ALL')+'($'+(j+q['length']-0x1)+')');continue;}const z={'eq':'=','ne':'<>','gt':'>','gte':'>=','lt':'<','lte':'<=','like':'like'},x='$'+(j+q[D(0x187)]);if(b==='like'){q[D(0x188)](E+'%'),Z['push'](D(0x18a)+A+')\x20like\x20lower('+x+')');continue;}q[D(0x188)](E),Z[D(0x188)](A+'\x20'+z[b]+'\x20'+x);}}return{'sql':Z[D(0x187)]?D(0x18b)+Z[D(0x18c)](D(0x18d)):'','values':q};}function m(){const O=['null','exec','has','nin','fields','table','filter','filterable','type','NULL','length','push','FALSE','lower(','\x20WHERE\x20','join','\x20AND\x20','object','isArray','like','text','geom'];m=function(){return O;};return m();}function isRecord(P){const h=i;return typeof P===h(0x18e)&&P!==null&&!Array[h(0x18f)](P);}function isTruthy(P){return P===!![]||P==='true'||P==='1'||P===0x1;}function indexTypeFor(P,G){const L=i;if(G===L(0x190)||G==='ilike')return L(0x191);if(P===L(0x192)||P==='geometry')return'gist';return'btree';}
1
+ const a=f;import{fieldColumn,qi}from'./sql.js';import{ValidationError}from'../../../errors.js';import{autoIndex}from'./auto-index.js';const filterOperators=new Set(['eq','ne','gt','gte','lt',a(0x1b6),'in','nin',a(0x1b7),a(0x1b8),a(0x1b9)]);export function parseFilterQuery(p){const X=a,Z={...isRecord(p['filter'])?p[X(0x1ba)]:{}};for(const [A,I]of Object['entries'](p)){const j=/^filter\[([^\]]+)\](?:\[([^\]]+)\])?$/['exec'](A);if(!j)continue;const [,D,o]=j;if(!D)continue;if(!o){Z[D]=I;continue;}if(!filterOperators[X(0x1bb)](o))throw new ValidationError(X(0x1bc)+o);const R=isRecord(Z[D])?Z[D]:{};R[o]=(o==='in'||o===X(0x1bd))&&typeof I===X(0x1be)?I[X(0x1bf)](','):I,Z[D]=R;}return Object[X(0x1c0)](Z)[X(0x1c1)]?Z:undefined;}export function buildIndex(p,Z,A){for(const [I,j]of Object['entries'](Z??{})){const D=p['fields'][I];if(!D||D['filter']!==!![]&&D['filterable']!==!![])throw new ValidationError('Field\x20is\x20not\x20filterable:\x20'+I);A&&autoIndex(p['table'],fieldColumn(p,I),indexTypeFor(D['type'],'eq'),A);}}function f(p,Z){p=p-0x1b6;const A=s();let I=A[p];return I;}export function buildFilters(p,Z,A=0x1){const K=a,I=[],j=[];for(const [D,o]of Object[K(0x1c2)](Z??{})){const R=p['fields'][D];if(!R||R[K(0x1ba)]!==!![]&&R['filterable']!==!![])throw new ValidationError('Field\x20is\x20not\x20filterable:\x20'+D);const B=qi(fieldColumn(p,D)),H=isRecord(o)?o:{'eq':o};for(const [e,g]of Object[K(0x1c2)](H)){if(!filterOperators['has'](e))throw new ValidationError('Unsupported\x20filter\x20operator:\x20'+e);if((e==='like'||e===K(0x1b8))&&R['type']!=='string'&&R['type']!=='text')throw new ValidationError(K(0x1c3)+e+'\x20requires\x20a\x20text\x20field:\x20'+D);if(e===K(0x1b9)){I[K(0x1c4)](B+'\x20IS\x20'+(isTruthy(g)?'':K(0x1c5))+'NULL');continue;}if(e==='in'||e==='nin'){const E=Array['isArray'](g)?g:[g];if(E['length']===0x0){I['push'](e==='in'?'FALSE':K(0x1c6));continue;}j[K(0x1c4)](E),I['push'](B+'\x20'+(e==='in'?'=\x20ANY':K(0x1c7))+'($'+(A+j[K(0x1c1)]-0x1)+')');continue;}const N={'eq':'=','ne':'<>','gt':'>','gte':'>=','lt':'<','lte':'<=','like':K(0x1b7)},h='$'+(A+j['length']);if(e==='like'){j['push'](g+'%'),I[K(0x1c4)]('lower('+B+K(0x1c8)+h+')');continue;}j['push'](g),I['push'](B+'\x20'+N[e]+'\x20'+h);}}return{'sql':I[K(0x1c1)]?'\x20WHERE\x20'+I['join']('\x20AND\x20'):'','values':j};}function s(){const V=['lte','like','ilike','null','filter','has','Unsupported\x20filter\x20operator:\x20','nin','string','split','keys','length','entries','Operator\x20','push','NOT\x20','TRUE','<>\x20ALL',')\x20like\x20lower(','isArray','geom','gist','btree'];s=function(){return V;};return s();}function isRecord(p){const Q=a;return typeof p==='object'&&p!==null&&!Array[Q(0x1c9)](p);}function isTruthy(p){return p===!![]||p==='true'||p==='1'||p===0x1;}function indexTypeFor(p,Z){const G=a;if(Z==='like'||Z===G(0x1b8))return'text';if(p===G(0x1ca)||p==='geometry')return G(0x1cb);return G(0x1cc);}
@@ -1 +1 @@
1
- function C(P,G){P=P-0x175;const j=m();let Z=j[P];return Z;}function m(){const X=['public','Authentication\x20required','type','permissions','includes','Missing\x20permission:\x20'];m=function(){return X;};return m();}import{ForbiddenError}from'../../../errors.js';import{getContext}from'../../../index.js';export function assertOperation(P,G,j){const p=C,Z=getContext()['config'];if(Z['debug'])return;if(!P['operations']['includes'](G))throw new ForbiddenError(P['name']+'.'+G+'\x20is\x20disabled');if(P['access']!==p(0x175)&&j===undefined)throw new ForbiddenError(p(0x176));if(P['access']==='admin'&&j?.[p(0x177)]!=='admin')throw new ForbiddenError('Admin\x20access\x20required');if(j?.['type']!=='admin'){const q=(P['permission']??P['name'])+':'+G;if(!j?.[p(0x178)]?.[p(0x179)](q))throw new ForbiddenError(p(0x17a)+q);}}
1
+ import{ForbiddenError}from'../../../errors.js';function s(){const o=['config','public','admin','type','includes','Missing\x20permission:\x20'];s=function(){return o;};return s();}function f(p,Z){p=p-0x86;const A=s();let I=A[p];return I;}import{getContext}from'../../../index.js';export function assertOperation(p,Z,A){const D=f,I=getContext()[D(0x86)];if(I['debug'])return;if(!p['operations']['includes'](Z))throw new ForbiddenError(p['name']+'.'+Z+'\x20is\x20disabled');if(p['access']!==D(0x87)&&A===undefined)throw new ForbiddenError('Authentication\x20required');if(p['access']===D(0x88)&&A?.[D(0x89)]!==D(0x88))throw new ForbiddenError('Admin\x20access\x20required');if(A?.['type']!==D(0x88)){const j=(p['permission']??p['name'])+':'+Z;if(!A?.['permissions']?.[D(0x8a)](j))throw new ForbiddenError(D(0x8b)+j);}}
@@ -1 +1 @@
1
- function C(P,G){P=P-0xe7;const j=m();let Z=j[P];return Z;}import{ValidationError}from'../../../errors.js';import{qi}from'./sql.js';const scopeCache=new Map(),CACHE_TTL_MS=0x7530;export function clearResourceScopeCache(P,G){const E=C;if(P&&G){scopeCache[E(0xe7)](P+':'+G);return;}if(P){for(const j of scopeCache['keys']()){if(j['startsWith'](P+':'))scopeCache['delete'](j);}return;}scopeCache[E(0xe8)]();}function m(){const y=['delete','clear','SELECT\x20DISTINCT\x20ras.scope,\x20ras.value\x0a\x20\x20\x20\x20\x20FROM\x20admin.role_access_scope\x20ras\x0a\x20\x20\x20\x20\x20WHERE\x20ras.resource\x20=\x20$2\x0a\x20\x20\x20\x20\x20\x20\x20AND\x20ras.enabled\x20=\x20TRUE\x0a\x20\x20\x20\x20\x20\x20\x20AND\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20ras.user_id\x20=\x20$1\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20OR\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ras.user_id\x20IS\x20NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20ras.role_id\x20IN\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20SELECT\x20ur.role_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20admin.user_roles\x20ur\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20ur.user_uid\x20=\x20$1\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20(ur.expiration\x20IS\x20NULL\x20OR\x20ur.expiration\x20>=\x20CURRENT_DATE)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x0a\x20\x20\x20\x20\x20\x20\x20)','scope','set','now','key','user_id','user_uid','created_by','name','push','\x20=\x20$','(FALSE)','join'];m=function(){return y;};return m();}async function loadScopeRows(P,G,j){const z=C,Z=P+':'+G,q=scopeCache['get'](Z);if(q&&q['expiresAt']>Date['now']())return q['promise'];const p=j['query'](z(0xe9),[P,G])['then'](({rows:X})=>{const x=z,F=new Map();for(const A of X){const H=F['get'](A['scope'])??[];if(Array['isArray'](A['value']))H['push'](...A['value']);else{if(A['value']!==null&&A['value']!==undefined)H['push'](A['value']);}F['set'](A[x(0xea)],H);}return F;})['catch'](X=>{scopeCache['delete'](Z);throw X;});return scopeCache[z(0xeb)](Z,{'expiresAt':Date[z(0xec)]()+CACHE_TTL_MS,'promise':p}),p;}export async function getUserResourceScopes(P,G,j){const Z=await loadScopeRows(P,G,j);return Object['fromEntries']([...Z]['map'](([q,p])=>[q,q==='me'?P:p]));}function columnForScope(P,G){const o=C;if(G===P['name'])return P[o(0xed)];if(G==='me'){const Z=[o(0xee),o(0xef),'owner_id',o(0xf0)]['find'](q=>P['fields'][q]);if(!Z)throw new ValidationError('Cannot\x20apply\x20\x22me\x22\x20scope\x20to\x20resource\x20without\x20an\x20owner\x20field:\x20'+P[o(0xf1)]);return P['fields'][Z]?.['column']??Z;}const j=P['fields'][G];if(!j)return'';return j['column']??G;}export async function buildUserResourceScopeFilter(P,G,j,Z){const i=C;if(!G||G['type']==='admin')return{'sql':'','values':[]};const q=await loadScopeRows(G['id'],P[i(0xf1)],j),p=[],X=[];for(const [F,A]of q){const H=columnForScope(P,F);if(!H){p['push']('(FALSE)');continue;}const b='t.'+qi(H);if(F==='me'){X['push'](G['id']),p[i(0xf2)]('('+b+i(0xf3)+(Z+X['length']-0x1)+')');continue;}if(A['length']===0x0){p['push'](i(0xf4));continue;}X['push'](A),p['push']('('+b+'\x20=\x20ANY($'+(Z+X['length']-0x1)+'))');}return{'sql':p[i(0xf5)]('\x20AND\x20'),'values':X};}
1
+ import{ValidationError}from'../../../errors.js';import{qi}from'./sql.js';function f(p,Z){p=p-0xe3;const A=s();let I=A[p];return I;}const scopeCache=new Map(),CACHE_TTL_MS=0x7530;export function clearResourceScopeCache(p,Z){const g=f;if(p&&Z){scopeCache['delete'](p+':'+Z);return;}if(p){for(const A of scopeCache['keys']()){if(A['startsWith'](p+':'))scopeCache['delete'](A);}return;}scopeCache[g(0xe3)]();}function s(){const K=['clear','get','promise','query','scope','value','set','fromEntries','name','key','user_uid','created_by','fields','type','admin','\x20=\x20$','push','length','\x20AND\x20'];s=function(){return K;};return s();}async function loadScopeRows(p,Z,A){const N=f,I=p+':'+Z,j=scopeCache[N(0xe4)](I);if(j&&j['expiresAt']>Date['now']())return j[N(0xe5)];const D=A[N(0xe6)]('SELECT\x20DISTINCT\x20ras.scope,\x20ras.value\x0a\x20\x20\x20\x20\x20FROM\x20admin.role_access_scope\x20ras\x0a\x20\x20\x20\x20\x20WHERE\x20ras.resource\x20=\x20$2\x0a\x20\x20\x20\x20\x20\x20\x20AND\x20ras.enabled\x20=\x20TRUE\x0a\x20\x20\x20\x20\x20\x20\x20AND\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20ras.user_id\x20=\x20$1\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20OR\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20ras.user_id\x20IS\x20NULL\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20ras.role_id\x20IN\x20(\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20SELECT\x20ur.role_id\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20FROM\x20admin.user_roles\x20ur\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20WHERE\x20ur.user_uid\x20=\x20$1\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20AND\x20(ur.expiration\x20IS\x20NULL\x20OR\x20ur.expiration\x20>=\x20CURRENT_DATE)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20)\x0a\x20\x20\x20\x20\x20\x20\x20)',[p,Z])['then'](({rows:o})=>{const h=N,R=new Map();for(const B of o){const H=R['get'](B[h(0xe7)])??[];if(Array['isArray'](B['value']))H['push'](...B['value']);else{if(B['value']!==null&&B[h(0xe8)]!==undefined)H['push'](B['value']);}R['set'](B[h(0xe7)],H);}return R;})['catch'](o=>{scopeCache['delete'](I);throw o;});return scopeCache[N(0xe9)](I,{'expiresAt':Date['now']()+CACHE_TTL_MS,'promise':D}),D;}export async function getUserResourceScopes(p,Z,A){const E=f,I=await loadScopeRows(p,Z,A);return Object[E(0xea)]([...I]['map'](([j,D])=>[j,j==='me'?p:D]));}function columnForScope(p,Z){const a=f;if(Z===p[a(0xeb)])return p[a(0xec)];if(Z==='me'){const I=['user_id',a(0xed),'owner_id',a(0xee)]['find'](j=>p[a(0xef)][j]);if(!I)throw new ValidationError('Cannot\x20apply\x20\x22me\x22\x20scope\x20to\x20resource\x20without\x20an\x20owner\x20field:\x20'+p[a(0xeb)]);return p['fields'][I]?.['column']??I;}const A=p['fields'][Z];if(!A)return'';return A['column']??Z;}export async function buildUserResourceScopeFilter(p,Z,A,I){const X=f;if(!Z||Z[X(0xf0)]===X(0xf1))return{'sql':'','values':[]};const j=await loadScopeRows(Z['id'],p[X(0xeb)],A),D=[],o=[];for(const [R,B]of j){const H=columnForScope(p,R);if(!H){D['push']('(FALSE)');continue;}const e='t.'+qi(H);if(R==='me'){o['push'](Z['id']),D['push']('('+e+X(0xf2)+(I+o['length']-0x1)+')');continue;}if(B['length']===0x0){D[X(0xf3)]('(FALSE)');continue;}o[X(0xf3)](B),D['push']('('+e+'\x20=\x20ANY($'+(I+o[X(0xf4)]-0x1)+'))');}return{'sql':D['join'](X(0xf5)),'values':o};}
@@ -1 +1 @@
1
- function m(){const H=['startsWith','slice','sortable','\x20ORDER\x20BY\x20'];m=function(){return H;};return m();}import{fieldColumn,qi}from'./sql.js';import{ValidationError}from'../../../errors.js';function C(P,G){P=P-0x105;const j=m();let Z=j[P];return Z;}export function buildSort(P,G){const A=C;if(!G?.['length'])return'';typeof G==='string'&&(G=[G]);const j=G['map'](Z=>{const F=C,q=Z[F(0x105)]('-'),p=q?Z[F(0x106)](0x1):Z,X=P['fields'][p];if(!X||X[F(0x107)]!==!![])throw new ValidationError('Field\x20is\x20not\x20sortable:\x20'+p);return qi(fieldColumn(P,p))+'\x20'+(q?'DESC':'ASC');});return A(0x108)+j['join'](',\x20');}
1
+ function s(){const H=['string','ASC','join'];s=function(){return H;};return s();}import{fieldColumn,qi}from'./sql.js';function f(p,Z){p=p-0x67;const A=s();let I=A[p];return I;}import{ValidationError}from'../../../errors.js';export function buildSort(p,Z){const R=f;if(!Z?.['length'])return'';typeof Z===R(0x67)&&(Z=[Z]);const A=Z['map'](I=>{const B=R,j=I['startsWith']('-'),D=j?I['slice'](0x1):I,o=p['fields'][D];if(!o||o['sortable']!==!![])throw new ValidationError('Field\x20is\x20not\x20sortable:\x20'+D);return qi(fieldColumn(p,D))+'\x20'+(j?'DESC':B(0x68));});return'\x20ORDER\x20BY\x20'+A[R(0x69)](',\x20');}
@@ -1 +1 @@
1
- const X=C;import{ValidationError}from'../../../errors.js';export const quoteIdentifier=P=>'\x22'+P[X(0x14f)](/"/g,'\x22\x22')+'\x22';export const quoteTable=P=>P['split']('.')['map'](quoteIdentifier)['join']('.');export function fieldColumn(P,G){const F=X;if(G===P['key'])return P['key'];const j=P[F(0x150)][G];if(!j)throw new ValidationError('Unknown\x20field:\x20'+G);return j['column']??G;}export function readableFields(P,G){const A=X,j=Object['entries'](P['fields'])['filter'](([,Z])=>Z[A(0x151)]!==![]&&Z[A(0x152)]!==![]&&(G?(Z['scope']??A(0x153))===G:!![]))['map'](([Z,q])=>quoteIdentifier(q['column']??Z)+A(0x154)+quoteIdentifier(Z));return!P['fields'][P[A(0x155)]]&&j['unshift'](quoteIdentifier(P['key'])),j;}function C(P,G){P=P-0x14f;const j=m();let Z=j[P];return Z;}export function writableData(P,G){const H=X,j=[];for(const [Z,q]of Object['entries'](G)){const p=P['fields'][Z];if(!p||p[H(0x156)]===![]||p[H(0x157)]===![])throw new ValidationError(H(0x158)+Z);if((p['write']??p['writable'])!==!![])continue;if(p['type']==='date'&&!G[Z])continue;j['push']([p['column']??Z,q]);}return j;}export const qi=quoteIdentifier;function m(){const b=['replace','fields','read','readable','all','\x20AS\x20','key','write','writable','Field\x20is\x20not\x20writable:\x20'];m=function(){return b;};return m();}export const qt=quoteTable;
1
+ const o=f;import{ValidationError}from'../../../errors.js';export const quoteIdentifier=p=>'\x22'+p['replace'](/"/g,'\x22\x22')+'\x22';function s(){const e=['split','Unknown\x20field:\x20','fields','read','scope','column','unshift','write'];s=function(){return e;};return s();}export const quoteTable=p=>p[o(0x1cd)]('.')['map'](quoteIdentifier)['join']('.');function f(p,Z){p=p-0x1cd;const A=s();let I=A[p];return I;}export function fieldColumn(p,Z){const R=o;if(Z===p['key'])return p['key'];const A=p['fields'][Z];if(!A)throw new ValidationError(R(0x1ce)+Z);return A['column']??Z;}export function readableFields(p,Z){const B=o,A=Object['entries'](p[B(0x1cf)])['filter'](([,I])=>I[B(0x1d0)]!==![]&&I['readable']!==![]&&(Z?(I[B(0x1d1)]??'all')===Z:!![]))['map'](([I,j])=>quoteIdentifier(j[B(0x1d2)]??I)+'\x20AS\x20'+quoteIdentifier(I));return!p['fields'][p['key']]&&A[B(0x1d3)](quoteIdentifier(p['key'])),A;}export function writableData(p,Z){const H=o,A=[];for(const [I,j]of Object['entries'](Z)){const D=p['fields'][I];if(!D||D[H(0x1d4)]===![]||D['writable']===![])throw new ValidationError('Field\x20is\x20not\x20writable:\x20'+I);if((D[H(0x1d4)]??D['writable'])!==!![])continue;if(D['type']==='date'&&!Z[I])continue;A['push']([D[H(0x1d2)]??I,j]);}return A;}export const qi=quoteIdentifier;export const qt=quoteTable;
@@ -1 +1 @@
1
- function m(){const i=['sql','countDistinct','true','))::int\x20AS\x20\x22','sum','field','avg','where','\x20AND\x20','\x20WHERE\x20','default','scopes','keys','fields','search',')\x20LIKE\x20$','values','scope','map','SELECT\x20','table','replace','NULL'];m=function(){return i;};return m();}function C(P,G){P=P-0x1da;const j=m();let Z=j[P];return Z;}import{buildFilters}from'./filters.js';import{qt}from'./sql.js';const defaultSummary={'count':{'aggregate':'count'}};export function buildSummary(P,G,j,Z){const o=C,q={...defaultSummary,...P['summary']??{}},p=Object['entries'](q)['map'](([E,z])=>{const x=C;if(x(0x1da)in z)return'('+z['sql']+')\x20AS\x20\x22'+E+'\x22';switch(z['aggregate']){case'count':return'(COUNT(*)\x20FILTER\x20(where\x20'+(z['where']??'true')+'))::int\x20AS\x20\x22'+E+'\x22';case x(0x1db):return'(COUNT(DISTINCT\x20t.'+qt(z['field'])+')\x20FILTER\x20(where\x20'+(z['where']??x(0x1dc))+x(0x1dd)+E+'\x22';case x(0x1de):return'SUM('+z[x(0x1df)]+')\x20FILTER\x20(where\x20'+(z['where']??'true')+')\x20AS\x20\x22'+E+'\x22';case x(0x1e0):return'AVG('+z['field']+')\x20FILTER\x20(where\x20'+(z['where']??x(0x1dc))+')\x20AS\x20\x22'+E+'\x22';case'min':return'MIN('+z['field']+')\x20FILTER\x20(where\x20'+(z[x(0x1e1)]??x(0x1dc))+')\x20AS\x20\x22'+E+'\x22';case'max':return'MAX('+z['field']+')\x20FILTER\x20(where\x20'+(z['where']??x(0x1dc))+')\x20AS\x20\x22'+E+'\x22';}}),X=buildFilters(P,G['filter']);P['where']&&(X['sql']+=(X['sql']?o(0x1e2):o(0x1e3))+('('+P[o(0x1e1)]+')'));const F=G['scope']||(P['scopes']?.['default']?o(0x1e4):undefined);F&&(X['sql']+=(X[o(0x1da)]?o(0x1e2):o(0x1e3))+('('+(P[o(0x1e5)]?.[F]||'true')+')'));const A=P['searchable']||Object[o(0x1e6)](P[o(0x1e7)])['filter'](E=>P['fields'][E]?.['searchable']);G[o(0x1e8)]&&A['length']&&(X['values']['push'](G['search']['toLowerCase']()+'%'),X['sql']+=(X['sql']?o(0x1e2):o(0x1e3))+('\x20('+A['map'](E=>'lower('+qt(E)+o(0x1e9)+X[o(0x1ea)]['length'])['join']('\x20OR\x20')+')'));Z?.[o(0x1da)]&&(X['sql']+=(X['sql']?'\x20AND\x20':'\x20WHERE\x20')+('('+Z[o(0x1da)]+')'),X['values']['push'](...Z['values']));const H=P['joins']?.['filter'](E=>E[o(0x1eb)]!=='item')[o(0x1ec)](E=>E['sql']+'\x20')['join']('\x20')||'',b=o(0x1ed)+p['join'](',\x20')+'\x20'+('FROM\x20'+qt(P[o(0x1ee)])+'\x20t\x20')+(H+'\x20'+X[o(0x1da)][o(0x1ef)](/:uid/g,'\x27'+(j?.['id']??o(0x1f0))+'\x27'));return{'sql':b,'values':X['values']};}
1
+ function f(p,Z){p=p-0x1ce;const A=s();let I=A[p];return I;}function s(){const a=['aggregate','where','))::int\x20AS\x20\x22',')\x20AS\x20\x22',')\x20FILTER\x20(where\x20','true','MIN(','max','filter','\x20AND\x20','default','keys','searchable','push','sql','values','item','map','SELECT\x20'];s=function(){return a;};return s();}import{buildFilters}from'./filters.js';import{qt}from'./sql.js';const defaultSummary={'count':{'aggregate':'count'}};export function buildSummary(p,Z,A,I){const E=f,j={...defaultSummary,...p['summary']??{}},D=Object['entries'](j)['map'](([g,N])=>{const h=f;if('sql'in N)return'('+N['sql']+')\x20AS\x20\x22'+g+'\x22';switch(N[h(0x1ce)]){case'count':return'(COUNT(*)\x20FILTER\x20(where\x20'+(N[h(0x1cf)]??'true')+h(0x1d0)+g+'\x22';case'countDistinct':return'(COUNT(DISTINCT\x20t.'+qt(N['field'])+')\x20FILTER\x20(where\x20'+(N['where']??'true')+'))::int\x20AS\x20\x22'+g+'\x22';case'sum':return'SUM('+N['field']+')\x20FILTER\x20(where\x20'+(N['where']??'true')+h(0x1d1)+g+'\x22';case'avg':return'AVG('+N['field']+h(0x1d2)+(N['where']??h(0x1d3))+h(0x1d1)+g+'\x22';case'min':return h(0x1d4)+N['field']+')\x20FILTER\x20(where\x20'+(N['where']??'true')+h(0x1d1)+g+'\x22';case h(0x1d5):return'MAX('+N['field']+')\x20FILTER\x20(where\x20'+(N['where']??'true')+h(0x1d1)+g+'\x22';}}),o=buildFilters(p,Z[E(0x1d6)]);p['where']&&(o['sql']+=(o['sql']?E(0x1d7):'\x20WHERE\x20')+('('+p['where']+')'));const R=Z['scope']||(p['scopes']?.[E(0x1d8)]?'default':undefined);R&&(o['sql']+=(o['sql']?'\x20AND\x20':'\x20WHERE\x20')+('('+(p['scopes']?.[R]||'true')+')'));const B=p['searchable']||Object[E(0x1d9)](p['fields'])[E(0x1d6)](g=>p['fields'][g]?.[E(0x1da)]);Z['search']&&B['length']&&(o['values'][E(0x1db)](Z['search']['toLowerCase']()+'%'),o[E(0x1dc)]+=(o[E(0x1dc)]?E(0x1d7):'\x20WHERE\x20')+('\x20('+B['map'](g=>'lower('+qt(g)+')\x20LIKE\x20$'+o[E(0x1dd)]['length'])['join']('\x20OR\x20')+')'));I?.['sql']&&(o['sql']+=(o[E(0x1dc)]?E(0x1d7):'\x20WHERE\x20')+('('+I[E(0x1dc)]+')'),o['values']['push'](...I['values']));const H=p['joins']?.['filter'](g=>g['scope']!==E(0x1de))[E(0x1df)](g=>g['sql']+'\x20')['join']('\x20')||'',e=E(0x1e0)+D['join'](',\x20')+'\x20'+('FROM\x20'+qt(p['table'])+'\x20t\x20')+(H+'\x20'+o[E(0x1dc)]['replace'](/:uid/g,'\x27'+(A?.['id']??'NULL')+'\x27'));return{'sql':e,'values':o['values']};}
@@ -1 +1 @@
1
- function C(P,G){P=P-0x1a5;const j=m();let Z=j[P];return Z;}function m(){const j=['headers','connection','pop'];m=function(){return j;};return m();}const G=C,getIP=P=>(P['headers']?.['x-real-ip']||P[G(0x1a5)]?.['x-forwarded-for']||P['ip']||P[G(0x1a6)]?.['remoteAddress']||'')['split'](':')[G(0x1a7)]();export default getIP;
1
+ function f(p,Z){p=p-0xb7;const A=s();let I=A[p];return I;}const Z=f,getIP=p=>(p['headers']?.['x-real-ip']||p[Z(0xb7)]?.[Z(0xb8)]||p['ip']||p[Z(0xb9)]?.[Z(0xba)]||'')['split'](':')['pop']();function s(){const A=['headers','x-forwarded-for','connection','remoteAddress'];s=function(){return A;};return s();}export default getIP;
@@ -1,18 +1,18 @@
1
- CREATE SCHEMA IF NOT EXISTS admin;
2
-
3
- DO $$
4
- BEGIN
5
- IF to_regclass('crm.notes') IS NOT NULL
6
- AND to_regclass('admin.notes') IS NULL THEN
7
- ALTER TABLE crm.notes SET SCHEMA admin;
8
- END IF;
9
-
10
- IF to_regclass('crm.files') IS NOT NULL
11
- AND to_regclass('admin.files') IS NULL THEN
12
- ALTER TABLE crm.files SET SCHEMA admin;
13
- END IF;
14
- END
15
- $$;
16
-
17
- ALTER INDEX IF EXISTS crm_notes_resource_idx RENAME TO admin_notes_resource_idx;
1
+ CREATE SCHEMA IF NOT EXISTS admin;
2
+
3
+ DO $$
4
+ BEGIN
5
+ IF to_regclass('crm.notes') IS NOT NULL
6
+ AND to_regclass('admin.notes') IS NULL THEN
7
+ ALTER TABLE crm.notes SET SCHEMA admin;
8
+ END IF;
9
+
10
+ IF to_regclass('crm.files') IS NOT NULL
11
+ AND to_regclass('admin.files') IS NULL THEN
12
+ ALTER TABLE crm.files SET SCHEMA admin;
13
+ END IF;
14
+ END
15
+ $$;
16
+
17
+ ALTER INDEX IF EXISTS crm_notes_resource_idx RENAME TO admin_notes_resource_idx;
18
18
  ALTER INDEX IF EXISTS crm_notes_uid_idx RENAME TO admin_notes_uid_idx;
@@ -1,19 +1,19 @@
1
- CREATE SCHEMA IF NOT EXISTS admin;
2
-
3
- CREATE TABLE IF NOT EXISTS admin.settings (
4
- id text PRIMARY KEY DEFAULT next_id(),
5
- resource text NOT NULL DEFAULT 'system',
6
- resource_id text,
7
- key text NOT NULL,
8
- value jsonb,
9
- updated_by text,
10
- updated_at timestamptz NOT NULL DEFAULT now(),
11
- created_by text,
12
- created_at timestamptz NOT NULL DEFAULT now()
13
- );
14
-
15
- DROP INDEX IF EXISTS settings_resource_key_uidx;
16
-
17
- CREATE UNIQUE INDEX settings_resource_key_uidx
18
- ON admin.settings (resource, resource_id, key)
1
+ CREATE SCHEMA IF NOT EXISTS admin;
2
+
3
+ CREATE TABLE IF NOT EXISTS admin.settings (
4
+ id text PRIMARY KEY DEFAULT next_id(),
5
+ resource text NOT NULL DEFAULT 'system',
6
+ resource_id text,
7
+ key text NOT NULL,
8
+ value jsonb,
9
+ updated_by text,
10
+ updated_at timestamptz NOT NULL DEFAULT now(),
11
+ created_by text,
12
+ created_at timestamptz NOT NULL DEFAULT now()
13
+ );
14
+
15
+ DROP INDEX IF EXISTS settings_resource_key_uidx;
16
+
17
+ CREATE UNIQUE INDEX settings_resource_key_uidx
18
+ ON admin.settings (resource, resource_id, key)
19
19
  NULLS NOT DISTINCT;
@@ -1,2 +1,2 @@
1
- ALTER TABLE admin.role_access_scope
1
+ ALTER TABLE admin.role_access_scope
2
2
  ALTER COLUMN role_id DROP NOT NULL;
package/package.json CHANGED
@@ -1,93 +1,93 @@
1
- {
2
- "name": "@opengis/fcore",
3
- "version": "0.0.27",
4
- "description": "Reusable backend foundation for OpenGIS Node.js applications",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "files": [
9
- "dist",
10
- "migrations",
11
- "README.md",
12
- "LICENSE"
13
- ],
14
- "exports": {
15
- ".": {
16
- "types": "./dist/index.d.ts",
17
- "import": "./dist/index.js"
18
- },
19
- "./fastify": {
20
- "types": "./dist/fastify.d.ts",
21
- "import": "./dist/fastify.js"
22
- },
23
- "./migrate": {
24
- "types": "./dist/migrations/runner.d.ts",
25
- "import": "./dist/migrations/runner.js"
26
- }
27
- },
28
- "bin": {
29
- "fcore-migrate": "./dist/migrations/cli.js",
30
- "fcore-adduser": "./dist/modules/auth/adduser-cli.js",
31
- "fcore-passwd": "./dist/modules/auth/passwd-cli.js",
32
- "fcore-permission": "./dist/modules/auth/permission-cli.js"
33
- },
34
- "scripts": {
35
- "clean": "rm -rf dist",
36
- "build": "npm run clean && tsc -p tsconfig.json && node scripts/obfuscate.mjs",
37
- "typecheck": "tsc -p tsconfig.json --noEmit",
38
- "test": "node --test --import tsx test/**/*.test.ts",
39
- "test-env": "node --env-file=.env.test --test --import tsx test/**/env.test.ts",
40
- "dev": "bun ./server.ts",
41
- "adduser": "node --import tsx ./src/modules/auth/adduser-cli.ts",
42
- "passwd": "node --import tsx ./src/modules/auth/passwd-cli.ts",
43
- "permission": "node --import tsx ./src/modules/auth/permission-cli.ts",
44
- "migrate": "node --import tsx src/migrations/cli.ts",
45
- "migration-test": "node --env-file=.env.test --import tsx src/migrations/cli.ts",
46
- "prepublishOnly": "npm run build",
47
- "prepublishOnly1": "npm run build && npm test",
48
- "patch": "npm version patch && git push && npm publish",
49
- "minor": "npm version minor && git push && npm publish",
50
- "major": "npm version major && git push && npm publish"
51
- },
52
- "engines": {
53
- "node": ">=20"
54
- },
55
- "dependencies": {
56
- "@aws-sdk/client-s3": "3.1125.0",
57
- "@aws-sdk/lib-storage": "3.1125.0",
58
- "@fastify/cookie": "11.1.2",
59
- "@fastify/multipart": "10.1.1",
60
- "@fastify/passport": "4.0.2",
61
- "@fastify/rate-limit": "11.2.0",
62
- "@fastify/session": "11.1.2",
63
- "@sinclair/typebox": "^0.34.52",
64
- "apache-crypt": "1.2.6",
65
- "dotenv": "17.4.2",
66
- "fastify-session-redis-store": "7.1.2",
67
- "file-type": "22.0.2",
68
- "ioredis": "6.0.0",
69
- "jose": "^6.2.12",
70
- "otplib": "13.5.0",
71
- "pg": "8.23.0",
72
- "pino": "10.3.1",
73
- "pino-abstract-transport": "3.0.0",
74
- "qrcode": "1.5.4",
75
- "sharp": "0.35.4"
76
- },
77
- "peerDependencies": {
78
- "fastify": ">=5.12.1"
79
- },
80
- "devDependencies": {
81
- "@types/node": "22.20.1",
82
- "@types/passport": "1.0.17",
83
- "@types/passport-local": "1.0.38",
84
- "@types/pg": "8.23.1",
85
- "@types/qrcode": "1.5.6",
86
- "fastify": "5.12.1",
87
- "javascript-obfuscator": "5.6.0",
88
- "tsx": "4.23.13",
89
- "typescript": "7.0.2",
90
- "vitest": "4.1.11"
91
- },
92
- "license": "UNLICENSED"
1
+ {
2
+ "name": "@opengis/fcore",
3
+ "version": "0.0.28",
4
+ "description": "Reusable backend foundation for OpenGIS Node.js applications",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "migrations",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "./fastify": {
20
+ "types": "./dist/fastify.d.ts",
21
+ "import": "./dist/fastify.js"
22
+ },
23
+ "./migrate": {
24
+ "types": "./dist/migrations/runner.d.ts",
25
+ "import": "./dist/migrations/runner.js"
26
+ }
27
+ },
28
+ "bin": {
29
+ "fcore-migrate": "./dist/migrations/cli.js",
30
+ "fcore-adduser": "./dist/modules/auth/adduser-cli.js",
31
+ "fcore-passwd": "./dist/modules/auth/passwd-cli.js",
32
+ "fcore-permission": "./dist/modules/auth/permission-cli.js"
33
+ },
34
+ "scripts": {
35
+ "clean": "rm -rf dist",
36
+ "build": "npm run clean && tsc -p tsconfig.json && node scripts/obfuscate.mjs",
37
+ "typecheck": "tsc -p tsconfig.json --noEmit",
38
+ "test": "node --test --import tsx test/**/*.test.ts",
39
+ "test-env": "node --env-file=.env.test --test --import tsx test/**/env.test.ts",
40
+ "dev": "bun ./server.ts",
41
+ "adduser": "node --import tsx ./src/modules/auth/adduser-cli.ts",
42
+ "passwd": "node --import tsx ./src/modules/auth/passwd-cli.ts",
43
+ "permission": "node --import tsx ./src/modules/auth/permission-cli.ts",
44
+ "migrate": "node --import tsx src/migrations/cli.ts",
45
+ "migration-test": "node --env-file=.env.test --import tsx src/migrations/cli.ts",
46
+ "prepublishOnly": "npm run build",
47
+ "prepublishOnly1": "npm run build && npm test",
48
+ "patch": "npm version patch && git push && npm publish",
49
+ "minor": "npm version minor && git push && npm publish",
50
+ "major": "npm version major && git push && npm publish"
51
+ },
52
+ "engines": {
53
+ "node": ">=20"
54
+ },
55
+ "dependencies": {
56
+ "@aws-sdk/client-s3": "3.1125.0",
57
+ "@aws-sdk/lib-storage": "3.1125.0",
58
+ "@fastify/cookie": "11.1.2",
59
+ "@fastify/multipart": "10.1.1",
60
+ "@fastify/passport": "4.0.2",
61
+ "@fastify/rate-limit": "11.2.0",
62
+ "@fastify/session": "11.1.2",
63
+ "@sinclair/typebox": "^0.34.52",
64
+ "apache-crypt": "1.2.6",
65
+ "dotenv": "17.4.2",
66
+ "fastify-session-redis-store": "7.1.2",
67
+ "file-type": "22.0.2",
68
+ "ioredis": "6.0.0",
69
+ "jose": "^6.2.12",
70
+ "otplib": "13.5.0",
71
+ "pg": "8.23.0",
72
+ "pino": "10.3.1",
73
+ "pino-abstract-transport": "3.0.0",
74
+ "qrcode": "1.5.4",
75
+ "sharp": "0.35.4"
76
+ },
77
+ "peerDependencies": {
78
+ "fastify": ">=5.12.1"
79
+ },
80
+ "devDependencies": {
81
+ "@types/node": "22.20.1",
82
+ "@types/passport": "1.0.17",
83
+ "@types/passport-local": "1.0.38",
84
+ "@types/pg": "8.23.1",
85
+ "@types/qrcode": "1.5.6",
86
+ "fastify": "5.12.1",
87
+ "javascript-obfuscator": "5.6.0",
88
+ "tsx": "4.23.13",
89
+ "typescript": "7.0.2",
90
+ "vitest": "4.1.11"
91
+ },
92
+ "license": "UNLICENSED"
93
93
  }