ekwo-os 0.4.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 (361) hide show
  1. package/README.md +873 -0
  2. package/dist/args.d.ts +57 -0
  3. package/dist/args.d.ts.map +1 -0
  4. package/dist/args.js +134 -0
  5. package/dist/args.js.map +1 -0
  6. package/dist/assets/expected-objects.json +9432 -0
  7. package/dist/assets/migrations/20260911120000_core_companies.sql +260 -0
  8. package/dist/assets/migrations/20260911120100_accounts_journals.sql +211 -0
  9. package/dist/assets/migrations/20260911120200_contacts.sql +90 -0
  10. package/dist/assets/migrations/20260911120300_taxes.sql +146 -0
  11. package/dist/assets/migrations/20260911120400_entries.sql +338 -0
  12. package/dist/assets/migrations/20260911120500_documents.sql +279 -0
  13. package/dist/assets/migrations/20260911120600_payments_reconciliation.sql +251 -0
  14. package/dist/assets/migrations/20260911120700_bank.sql +178 -0
  15. package/dist/assets/migrations/20260911120800_analytics_attachments.sql +128 -0
  16. package/dist/assets/migrations/20260911120900_post_document.sql +279 -0
  17. package/dist/assets/migrations/20260911121000_reporting.sql +235 -0
  18. package/dist/assets/migrations/20260911121100_country_templates.sql +226 -0
  19. package/dist/assets/migrations/20260911121200_fec.sql +71 -0
  20. package/dist/assets/migrations/20260911130000_instance.sql +77 -0
  21. package/dist/assets/migrations/20260911130100_instance_members.sql +224 -0
  22. package/dist/assets/migrations/20260911140000_instance_admins.sql +112 -0
  23. package/dist/assets/migrations/20260911160000_tax_posting_templates_unique.sql +17 -0
  24. package/dist/assets/migrations/20260911170000_document_amount_paid.sql +82 -0
  25. package/dist/assets/migrations/20260911173000_post_payment.sql +122 -0
  26. package/dist/assets/migrations/20260911173100_sequence_counters_under_rls.sql +84 -0
  27. package/dist/assets/migrations/20260911183000_country_journal_defaults.sql +143 -0
  28. package/dist/assets/migrations/20260911193853_line_account_defaults.sql +274 -0
  29. package/dist/assets/migrations/20260911195054_products.sql +221 -0
  30. package/dist/assets/migrations/20260911210131_anon_surface.sql +85 -0
  31. package/dist/assets/migrations/20260912074712_country_packs.sql +318 -0
  32. package/dist/assets/migrations/20260912080311_report_code_and_region.sql +198 -0
  33. package/dist/assets/migrations/20260912081014_pack_certification_maintained.sql +31 -0
  34. package/dist/assets/migrations/20260912081015_pack_certification_backfill.sql +16 -0
  35. package/dist/assets/migrations/20260912090407_tax_report_boxes.sql +329 -0
  36. package/dist/assets/migrations/20260912091917_tax_on_base_value.sql +25 -0
  37. package/dist/assets/migrations/20260912091918_tax_engine_columns.sql +776 -0
  38. package/dist/assets/migrations/20260912094412_opening_and_closing.sql +759 -0
  39. package/dist/assets/migrations/20260912095825_charts_of_accounts.sql +326 -0
  40. package/dist/assets/migrations/20260912100412_financial_statements.sql +632 -0
  41. package/dist/assets/migrations/20260912104719_one_formula_evaluator.sql +209 -0
  42. package/dist/assets/migrations/20260912105720_entry_kind_appropriation.sql +26 -0
  43. package/dist/assets/migrations/20260912105721_appropriation_entry_kind.sql +444 -0
  44. package/dist/assets/migrations/20260912111751_document_rules.sql +274 -0
  45. package/dist/assets/migrations/20260912112132_cash_basis_vat_and_fx.sql +1189 -0
  46. package/dist/assets/migrations/20260913074512_modules.sql +493 -0
  47. package/dist/assets/migrations/20260913075903_asset_disposal_roles.sql +47 -0
  48. package/dist/assets/migrations/20260913083216_capabilities.sql +637 -0
  49. package/dist/assets/migrations/20260913083901_company_invitations.sql +262 -0
  50. package/dist/assets/migrations/20260913084402_user_preferences.sql +376 -0
  51. package/dist/assets/migrations/20260913084847_company_profile.sql +261 -0
  52. package/dist/assets/migrations/20260913085436_numbering_reads_the_pack.sql +235 -0
  53. package/dist/assets/migrations/20260913085932_api_keys.sql +303 -0
  54. package/dist/assets/migrations/20260913090216_fiscal_year_bounds.sql +159 -0
  55. package/dist/assets/migrations/20260913092527_entries_import.sql +219 -0
  56. package/dist/assets/migrations/20260913101536_null_safe_guards.sql +188 -0
  57. package/dist/assets/migrations/20260913102115_installer_is_named.sql +462 -0
  58. package/dist/assets/migrations/20260913102758_no_currency_default.sql +138 -0
  59. package/dist/assets/migrations/20260913103355_cash_basis_needs_a_box.sql +453 -0
  60. package/dist/assets/migrations/20260913104014_aged_balance_named_group.sql +79 -0
  61. package/dist/assets/migrations/20260913104232_foreign_key_indexes.sql +144 -0
  62. package/dist/assets/migrations/20260913105120_declared_no_reader.sql +41 -0
  63. package/dist/assets/migrations/20260913111407_pack_languages.sql +223 -0
  64. package/dist/assets/migrations/20260913112233_schema_comments_for_a_reader.sql +27 -0
  65. package/dist/assets/migrations/20260913114535_fec_opening_balances.sql +307 -0
  66. package/dist/assets/migrations/20260914103412_audit_log.sql +509 -0
  67. package/dist/assets/migrations/20260914111907_pack_upgrade.sql +428 -0
  68. package/dist/assets/migrations/20260914120500_rounding_reads_the_currency.sql +206 -0
  69. package/dist/assets/migrations/20260914121200_amounts_round_at_the_currency.sql +2403 -0
  70. package/dist/assets/migrations/20260914134325_schema_version_0_2_0.sql +36 -0
  71. package/dist/assets/migrations/20260914143915_accounts_in_use.sql +428 -0
  72. package/dist/assets/migrations/20260914144731_account_code_frozen.sql +99 -0
  73. package/dist/assets/migrations/20260914151207_schema_grants_its_own_rights.sql +284 -0
  74. package/dist/assets/migrations/20260914152840_pack_upgrade_records_its_own_line.sql +237 -0
  75. package/dist/assets/migrations/20260914163943_declaration_periodicity.sql +349 -0
  76. package/dist/assets/migrations/20260915094000_foreign_services_received.sql +37 -0
  77. package/dist/assets/migrations/20260915094500_mentions_read_a_foreign_service.sql +72 -0
  78. package/dist/assets/migrations/20260915153000_document_shares.sql +568 -0
  79. package/dist/assets/migrations/20260915160000_ec_sales_list.sql +181 -0
  80. package/dist/assets/migrations/20260915161842_pack_sources.sql +56 -0
  81. package/dist/assets/migrations/20260915170500_schema_version_0_3_0.sql +45 -0
  82. package/dist/assets/migrations/20260915174500_a_vat_category_is_a_code.sql +177 -0
  83. package/dist/assets/migrations/20260915180000_document_rule_references.sql +85 -0
  84. package/dist/assets/migrations/20260915181000_territories.sql +342 -0
  85. package/dist/assets/migrations/20260915181500_ec_sales_list_reads_the_territories.sql +222 -0
  86. package/dist/assets/migrations/20260915182000_intracom_triangular.sql +53 -0
  87. package/dist/assets/migrations/20260915182500_a_triangular_supply_says_reverse_charge.sql +99 -0
  88. package/dist/assets/migrations/20260915191200_a_document_knows_its_language.sql +633 -0
  89. package/dist/assets/migrations/20260915195000_a_price_that_holds_its_tax.sql +649 -0
  90. package/dist/assets/migrations/20260915200000_a_posting_names_its_boxes.sql +1004 -0
  91. package/dist/assets/migrations/20260916094500_a_company_files_more_than_one_declaration.sql +795 -0
  92. package/dist/assets/migrations/20260916103000_a_ledger_line_names_its_posting.sql +902 -0
  93. package/dist/assets/migrations/20260916123000_a_vocabulary_for_a_tax_that_is_not_a_vat.sql +144 -0
  94. package/dist/assets/migrations/20260916124000_a_box_can_be_a_rate_of_a_box.sql +525 -0
  95. package/dist/assets/migrations/20260916125000_a_tax_follows_the_territory.sql +1318 -0
  96. package/dist/assets/migrations/20260916126000_a_tax_point_and_its_exception.sql +1211 -0
  97. package/dist/assets/migrations/20260917090000_a_counterparty_that_learns.sql +561 -0
  98. package/dist/assets/migrations/20260917120000_what_the_money_pays.sql +545 -0
  99. package/dist/assets/migrations/20260917150000_a_filing_is_a_row.sql +488 -0
  100. package/dist/assets/migrations/20260917170000_when_it_is_due.sql +194 -0
  101. package/dist/assets/migrations/20260917180000_a_box_is_a_number_and_a_kind.sql +213 -0
  102. package/dist/assets/migrations/20260917190000_what_a_declaration_owes.sql +486 -0
  103. package/dist/assets/migrations/20260917200000_what_moved_after_it_went.sql +227 -0
  104. package/dist/assets/migrations/20260918090000_a_form_names_its_file.sql +27 -0
  105. package/dist/assets/migrations/20260918110000_a_deposit_and_what_came_back.sql +286 -0
  106. package/dist/assets/migrations/20260918113741_a_fourth_preset_is_named.sql +9 -0
  107. package/dist/assets/migrations/20260918113807_a_client_reads_and_hands_over.sql +96 -0
  108. package/dist/assets/migrations/20260918114322_two_definer_functions_check_their_caller.sql +75 -0
  109. package/dist/assets/migrations/20260918130000_every_company_somebody_keeps.sql +177 -0
  110. package/dist/assets/migrations/20260918140000_a_session_nobody_prepared.sql +40 -0
  111. package/dist/assets/migrations/20260918141107_a_line_keeps_the_tax_it_was_posted_with.sql +256 -0
  112. package/dist/assets/migrations/20260918141342_a_company_has_an_electronic_address.sql +66 -0
  113. package/dist/assets/migrations/20260918141605_an_invoice_reads_whole_from_the_views.sql +313 -0
  114. package/dist/assets/migrations/20260918141627_a_policy_asks_once.sql +132 -0
  115. package/dist/assets/migrations/20260918143352_a_suggestion_reads_the_words_once.sql +204 -0
  116. package/dist/assets/migrations/20260918143417_a_reference_of_the_caller_and_a_rehearsal.sql +115 -0
  117. package/dist/assets/migrations/20260918150712_a_company_leaves_with_its_books.sql +1119 -0
  118. package/dist/assets/migrations/20260918150931_a_statement_is_imported_once.sql +654 -0
  119. package/dist/assets/migrations/20260918161204_a_posted_document_does_not_move.sql +437 -0
  120. package/dist/assets/migrations/20260918161538_a_posted_entry_does_not_move.sql +252 -0
  121. package/dist/assets/migrations/20260918171946_an_entry_is_posted_by_post_entry.sql +289 -0
  122. package/dist/assets/migrations/20260918174312_schema_version_0_4_0.sql +53 -0
  123. package/dist/assets/modules/assets/module.json +13 -0
  124. package/dist/assets/modules/assets/supabase/migrations/20260913081447_assets.sql +1190 -0
  125. package/dist/assets/modules/assets/supabase/migrations/20260913104234_foreign_key_indexes.sql +47 -0
  126. package/dist/assets/modules/assets/supabase/migrations/20260913104500_assets_capabilities.sql +145 -0
  127. package/dist/assets/modules/assets/supabase/migrations/20260914122100_assets_round_at_the_currency.sql +564 -0
  128. package/dist/assets/modules/assets/supabase/migrations/20260914145012_assets_accounts_in_use.sql +37 -0
  129. package/dist/assets/modules/assets/supabase/migrations/20260914151530_assets_grants_its_own_rights.sql +63 -0
  130. package/dist/assets/modules/assets/supabase/migrations/20260918113912_assets_client_reads.sql +20 -0
  131. package/dist/assets/modules/assets/supabase/migrations/20260918150801_assets_leave_with_the_company.sql +41 -0
  132. package/dist/assets/modules/budgets/module.json +12 -0
  133. package/dist/assets/modules/budgets/supabase/migrations/20260913083012_budgets.sql +210 -0
  134. package/dist/assets/modules/budgets/supabase/migrations/20260913104233_foreign_key_indexes.sql +37 -0
  135. package/dist/assets/modules/budgets/supabase/migrations/20260913104501_budgets_capabilities.sql +72 -0
  136. package/dist/assets/modules/budgets/supabase/migrations/20260914122400_budgets_round_at_the_currency.sql +68 -0
  137. package/dist/assets/modules/budgets/supabase/migrations/20260914145048_budgets_accounts_in_use.sql +30 -0
  138. package/dist/assets/modules/budgets/supabase/migrations/20260914151812_budgets_grants_its_own_rights.sql +31 -0
  139. package/dist/assets/modules/budgets/supabase/migrations/20260918113954_budgets_client_reads.sql +20 -0
  140. package/dist/assets/modules/budgets/supabase/migrations/20260918150823_budgets_leave_with_the_company.sql +37 -0
  141. package/dist/assets/modules/schema/module.1.json +69 -0
  142. package/dist/assets/seed/00_currencies.sql +15 -0
  143. package/dist/assets/seed/00_territories.sql +280 -0
  144. package/dist/assets/seed/05_framework_generic.sql +110 -0
  145. package/dist/assets/seed/10_pack_be.sql +1284 -0
  146. package/dist/assets/seed/11_pack_fr.sql +1112 -0
  147. package/dist/assets/seed/12_pack_lu.sql +2484 -0
  148. package/dist/assets/seed/13_pack_ee.sql +733 -0
  149. package/dist/assets/seed/14_pack_gb.sql +796 -0
  150. package/dist/assets/seed/15_pack_us.sql +751 -0
  151. package/dist/assets/seed/90_demo_company.sql +368 -0
  152. package/dist/assets/seed/modules/assets/10_pack_be.sql +58 -0
  153. package/dist/assets/seed/modules/assets/11_pack_fr.sql +57 -0
  154. package/dist/assets/seed/modules/assets/14_pack_gb.sql +58 -0
  155. package/dist/assets/seed/modules/assets/15_pack_us.sql +60 -0
  156. package/dist/auth.d.ts +59 -0
  157. package/dist/auth.d.ts.map +1 -0
  158. package/dist/auth.js +134 -0
  159. package/dist/auth.js.map +1 -0
  160. package/dist/bin.d.ts +6 -0
  161. package/dist/bin.d.ts.map +1 -0
  162. package/dist/bin.js +8 -0
  163. package/dist/bin.js.map +1 -0
  164. package/dist/books.d.ts +60 -0
  165. package/dist/books.d.ts.map +1 -0
  166. package/dist/books.js +168 -0
  167. package/dist/books.js.map +1 -0
  168. package/dist/bootstrap.d.ts +236 -0
  169. package/dist/bootstrap.d.ts.map +1 -0
  170. package/dist/bootstrap.js +459 -0
  171. package/dist/bootstrap.js.map +1 -0
  172. package/dist/bundle.d.ts +27 -0
  173. package/dist/bundle.d.ts.map +1 -0
  174. package/dist/bundle.js +47 -0
  175. package/dist/bundle.js.map +1 -0
  176. package/dist/checklist.d.ts +35 -0
  177. package/dist/checklist.d.ts.map +1 -0
  178. package/dist/checklist.js +64 -0
  179. package/dist/checklist.js.map +1 -0
  180. package/dist/cli.d.ts +14 -0
  181. package/dist/cli.d.ts.map +1 -0
  182. package/dist/cli.js +318 -0
  183. package/dist/cli.js.map +1 -0
  184. package/dist/commands/company.d.ts +59 -0
  185. package/dist/commands/company.d.ts.map +1 -0
  186. package/dist/commands/company.js +287 -0
  187. package/dist/commands/company.js.map +1 -0
  188. package/dist/commands/contact.d.ts +9 -0
  189. package/dist/commands/contact.d.ts.map +1 -0
  190. package/dist/commands/contact.js +82 -0
  191. package/dist/commands/contact.js.map +1 -0
  192. package/dist/commands/demo.d.ts +19 -0
  193. package/dist/commands/demo.d.ts.map +1 -0
  194. package/dist/commands/demo.js +72 -0
  195. package/dist/commands/demo.js.map +1 -0
  196. package/dist/commands/doctor.d.ts +12 -0
  197. package/dist/commands/doctor.d.ts.map +1 -0
  198. package/dist/commands/doctor.js +68 -0
  199. package/dist/commands/doctor.js.map +1 -0
  200. package/dist/commands/document.d.ts +17 -0
  201. package/dist/commands/document.d.ts.map +1 -0
  202. package/dist/commands/document.js +217 -0
  203. package/dist/commands/document.js.map +1 -0
  204. package/dist/commands/init.d.ts +31 -0
  205. package/dist/commands/init.d.ts.map +1 -0
  206. package/dist/commands/init.js +535 -0
  207. package/dist/commands/init.js.map +1 -0
  208. package/dist/commands/login.d.ts +24 -0
  209. package/dist/commands/login.d.ts.map +1 -0
  210. package/dist/commands/login.js +128 -0
  211. package/dist/commands/login.js.map +1 -0
  212. package/dist/commands/migrate.d.ts +30 -0
  213. package/dist/commands/migrate.d.ts.map +1 -0
  214. package/dist/commands/migrate.js +115 -0
  215. package/dist/commands/migrate.js.map +1 -0
  216. package/dist/commands/module.d.ts +32 -0
  217. package/dist/commands/module.d.ts.map +1 -0
  218. package/dist/commands/module.js +285 -0
  219. package/dist/commands/module.js.map +1 -0
  220. package/dist/commands/pack.d.ts +22 -0
  221. package/dist/commands/pack.d.ts.map +1 -0
  222. package/dist/commands/pack.js +481 -0
  223. package/dist/commands/pack.js.map +1 -0
  224. package/dist/commands/payment.d.ts +15 -0
  225. package/dist/commands/payment.d.ts.map +1 -0
  226. package/dist/commands/payment.js +97 -0
  227. package/dist/commands/payment.js.map +1 -0
  228. package/dist/commands/register.d.ts +20 -0
  229. package/dist/commands/register.d.ts.map +1 -0
  230. package/dist/commands/register.js +134 -0
  231. package/dist/commands/register.js.map +1 -0
  232. package/dist/commands/status.d.ts +8 -0
  233. package/dist/commands/status.d.ts.map +1 -0
  234. package/dist/commands/status.js +134 -0
  235. package/dist/commands/status.js.map +1 -0
  236. package/dist/commands/whoami.d.ts +21 -0
  237. package/dist/commands/whoami.d.ts.map +1 -0
  238. package/dist/commands/whoami.js +133 -0
  239. package/dist/commands/whoami.js.map +1 -0
  240. package/dist/company.d.ts +16 -0
  241. package/dist/company.d.ts.map +1 -0
  242. package/dist/company.js +26 -0
  243. package/dist/company.js.map +1 -0
  244. package/dist/config.d.ts +24 -0
  245. package/dist/config.d.ts.map +1 -0
  246. package/dist/config.js +50 -0
  247. package/dist/config.js.map +1 -0
  248. package/dist/connection.d.ts +79 -0
  249. package/dist/connection.d.ts.map +1 -0
  250. package/dist/connection.js +116 -0
  251. package/dist/connection.js.map +1 -0
  252. package/dist/context.d.ts +47 -0
  253. package/dist/context.d.ts.map +1 -0
  254. package/dist/context.js +93 -0
  255. package/dist/context.js.map +1 -0
  256. package/dist/doctor.d.ts +45 -0
  257. package/dist/doctor.d.ts.map +1 -0
  258. package/dist/doctor.js +448 -0
  259. package/dist/doctor.js.map +1 -0
  260. package/dist/grants.d.ts +88 -0
  261. package/dist/grants.d.ts.map +1 -0
  262. package/dist/grants.js +174 -0
  263. package/dist/grants.js.map +1 -0
  264. package/dist/identity.d.ts +54 -0
  265. package/dist/identity.d.ts.map +1 -0
  266. package/dist/identity.js +132 -0
  267. package/dist/identity.js.map +1 -0
  268. package/dist/index.d.ts +44 -0
  269. package/dist/index.d.ts.map +1 -0
  270. package/dist/index.js +43 -0
  271. package/dist/index.js.map +1 -0
  272. package/dist/inventory.d.ts +155 -0
  273. package/dist/inventory.d.ts.map +1 -0
  274. package/dist/inventory.js +303 -0
  275. package/dist/inventory.js.map +1 -0
  276. package/dist/migrations.d.ts +76 -0
  277. package/dist/migrations.d.ts.map +1 -0
  278. package/dist/migrations.js +226 -0
  279. package/dist/migrations.js.map +1 -0
  280. package/dist/module/read.d.ts +91 -0
  281. package/dist/module/read.d.ts.map +1 -0
  282. package/dist/module/read.js +172 -0
  283. package/dist/module/read.js.map +1 -0
  284. package/dist/output.d.ts +110 -0
  285. package/dist/output.d.ts.map +1 -0
  286. package/dist/output.js +173 -0
  287. package/dist/output.js.map +1 -0
  288. package/dist/pack/certification.d.ts +27 -0
  289. package/dist/pack/certification.d.ts.map +1 -0
  290. package/dist/pack/certification.js +38 -0
  291. package/dist/pack/certification.js.map +1 -0
  292. package/dist/pack/compile.d.ts +75 -0
  293. package/dist/pack/compile.d.ts.map +1 -0
  294. package/dist/pack/compile.js +801 -0
  295. package/dist/pack/compile.js.map +1 -0
  296. package/dist/pack/filing.d.ts +48 -0
  297. package/dist/pack/filing.d.ts.map +1 -0
  298. package/dist/pack/filing.js +56 -0
  299. package/dist/pack/filing.js.map +1 -0
  300. package/dist/pack/read.d.ts +766 -0
  301. package/dist/pack/read.d.ts.map +1 -0
  302. package/dist/pack/read.js +2336 -0
  303. package/dist/pack/read.js.map +1 -0
  304. package/dist/pack/schema.d.ts +26 -0
  305. package/dist/pack/schema.d.ts.map +1 -0
  306. package/dist/pack/schema.js +181 -0
  307. package/dist/pack/schema.js.map +1 -0
  308. package/dist/pack/territories.d.ts +98 -0
  309. package/dist/pack/territories.d.ts.map +1 -0
  310. package/dist/pack/territories.js +0 -0
  311. package/dist/pack/territories.js.map +1 -0
  312. package/dist/pack/upgrade.d.ts +86 -0
  313. package/dist/pack/upgrade.d.ts.map +1 -0
  314. package/dist/pack/upgrade.js +76 -0
  315. package/dist/pack/upgrade.js.map +1 -0
  316. package/dist/pack/vat-codes.d.ts +273 -0
  317. package/dist/pack/vat-codes.d.ts.map +1 -0
  318. package/dist/pack/vat-codes.js +513 -0
  319. package/dist/pack/vat-codes.js.map +1 -0
  320. package/dist/profiles.d.ts +67 -0
  321. package/dist/profiles.d.ts.map +1 -0
  322. package/dist/profiles.js +187 -0
  323. package/dist/profiles.js.map +1 -0
  324. package/dist/prompt.d.ts +40 -0
  325. package/dist/prompt.d.ts.map +1 -0
  326. package/dist/prompt.js +120 -0
  327. package/dist/prompt.js.map +1 -0
  328. package/dist/registry.d.ts +84 -0
  329. package/dist/registry.d.ts.map +1 -0
  330. package/dist/registry.js +104 -0
  331. package/dist/registry.js.map +1 -0
  332. package/dist/rest.d.ts +81 -0
  333. package/dist/rest.d.ts.map +1 -0
  334. package/dist/rest.js +245 -0
  335. package/dist/rest.js.map +1 -0
  336. package/dist/schema.d.ts +15 -0
  337. package/dist/schema.d.ts.map +1 -0
  338. package/dist/schema.js +15 -0
  339. package/dist/schema.js.map +1 -0
  340. package/dist/seeds.d.ts +27 -0
  341. package/dist/seeds.d.ts.map +1 -0
  342. package/dist/seeds.js +47 -0
  343. package/dist/seeds.js.map +1 -0
  344. package/dist/session.d.ts +39 -0
  345. package/dist/session.d.ts.map +1 -0
  346. package/dist/session.js +92 -0
  347. package/dist/session.js.map +1 -0
  348. package/dist/sql.d.ts +48 -0
  349. package/dist/sql.d.ts.map +1 -0
  350. package/dist/sql.js +112 -0
  351. package/dist/sql.js.map +1 -0
  352. package/dist/status.d.ts +94 -0
  353. package/dist/status.d.ts.map +1 -0
  354. package/dist/status.js +120 -0
  355. package/dist/status.js.map +1 -0
  356. package/dist/ui.d.ts +55 -0
  357. package/dist/ui.d.ts.map +1 -0
  358. package/dist/ui.js +114 -0
  359. package/dist/ui.js.map +1 -0
  360. package/package.json +29 -0
  361. package/schema/output.1.json +613 -0
@@ -0,0 +1,509 @@
1
+ -- Ekwo OS — an append-only record of what was changed, by whom, and when.
2
+ --
3
+ -- Everything the ledger does is already immutable: an entry is posted once and
4
+ -- corrected by a reversal, never edited. What sat outside that guarantee is
5
+ -- everything *around* the ledger — the chart of accounts, the journals, the
6
+ -- taxes and the accounts they post to, the bank accounts, the contacts, the
7
+ -- products, the financial years, who is a member of a company and with which
8
+ -- role, which pack version the company holds. Those decide how every future
9
+ -- entry is booked, and until this migration nothing recorded that one of them
10
+ -- had moved. An auditor asking "who changed the VAT account on this tax, and
11
+ -- when" had no answer, and neither did the operator.
12
+ --
13
+ -- This is one table, one trigger function and a handful of triggers. It is
14
+ -- deliberately not `pgaudit`: that extension is unavailable under PGlite, so
15
+ -- none of this could be tested here, and its output goes to the Postgres log
16
+ -- — a file an application cannot query and a self-hosted operator often
17
+ -- cannot reach. An audit trail nobody can read is a promise, not a control.
18
+ --
19
+ -- Four decisions are worth stating.
20
+ --
21
+ -- **Append-only is enforced by a trigger, not only by row level security.**
22
+ -- Policies do not apply to the table owner, and on Supabase `service_role`
23
+ -- carries BYPASSRLS. A `before update or delete` trigger that raises holds for
24
+ -- everyone, owner included; the dated purge function lifts it for the duration
25
+ -- of its own transaction and for nothing else.
26
+ --
27
+ -- **`company_id` carries no foreign key.** The audit trail outlives the rows
28
+ -- it describes: a cascade from `companies` would delete the record of the
29
+ -- company's own deletion. It is indexed, and row level security reads it.
30
+ --
31
+ -- **The ledger is not audited.** `entries` and `entry_lines` are immutable
32
+ -- once posted and are corrected by a reversal, which is already a visible
33
+ -- act. What is recorded here is the *act* of posting, cancelling or reversing
34
+ -- — never the content of the entry, which the ledger itself holds.
35
+ --
36
+ -- **The installer's own bulk copy is not audited row by row.** Installing a
37
+ -- country pack copies a thousand accounts into a company; a thousand rows
38
+ -- saying "account created" carry no information the single `company_packs`
39
+ -- row does not. `is_installer()` is already the schema's name for the
40
+ -- migration runner, the seeds and `ekwo init`, so the trigger stands down for
41
+ -- it and for nothing else. A person, a machine key, or anyone connecting with
42
+ -- `psql` is audited.
43
+
44
+ -- ---------------------------------------------------------------------------
45
+ -- The table
46
+ -- ---------------------------------------------------------------------------
47
+
48
+ create type audit_operation as enum ('insert', 'update', 'delete');
49
+
50
+ comment on type audit_operation is
51
+ 'What happened to the row. The business act, when there is one, is named in audit_log.action.';
52
+
53
+ create table audit_log (
54
+ id bigint generated always as identity primary key,
55
+ occurred_at timestamptz not null default now(),
56
+ -- Who. `auth.uid()` for a person; a machine key answers with its own id and
57
+ -- no user, which is exactly the distinction an auditor needs.
58
+ actor_id uuid,
59
+ api_key_id uuid,
60
+ -- Which company the change belongs to. Null for the reference data of the
61
+ -- installation itself — the packs it holds, its administrators.
62
+ company_id uuid,
63
+ -- What.
64
+ table_name text not null,
65
+ record_id uuid,
66
+ record_key text not null,
67
+ operation audit_operation not null,
68
+ -- The business act, where the row change is one: `document_posted`,
69
+ -- `fiscal_year_closed`, `pack_upgraded`. Null for an ordinary edit.
70
+ action text,
71
+ old_values jsonb,
72
+ new_values jsonb,
73
+ constraint audit_log_has_a_subject check (length(table_name) > 0 and length(record_key) > 0)
74
+ );
75
+
76
+ comment on table audit_log is
77
+ 'Append-only record of every change to the configuration and reference data of a company, and of the acts that change the state of a document, a payment, a financial year or a pack. Written by trigger, never by a client; no update and no delete, for anyone.';
78
+ comment on column audit_log.actor_id is 'auth.uid() at the time of the change. Null when the change came from a machine key or from a direct connection.';
79
+ comment on column audit_log.api_key_id is 'The machine key presented in the transaction, when one was.';
80
+ comment on column audit_log.company_id is 'The company the change belongs to, and what row level security reads. No foreign key: the trail outlives the row it describes.';
81
+ comment on column audit_log.record_key is 'The natural key of the row — an account code, a country, a user id — so a deleted row is still identifiable.';
82
+ comment on column audit_log.action is 'The business act this change is, when it is one. Null for an ordinary edit.';
83
+ comment on column audit_log.old_values is 'The row before, as jsonb. Null on an insert. Secrets are replaced by null, never stored twice.';
84
+ comment on column audit_log.new_values is 'The row after, as jsonb. Null on a delete.';
85
+
86
+ create index audit_log_company_idx on audit_log (company_id, occurred_at desc);
87
+ create index audit_log_table_idx on audit_log (table_name, occurred_at desc);
88
+ create index audit_log_actor_idx on audit_log (actor_id, occurred_at desc);
89
+ create index audit_log_record_idx on audit_log (table_name, record_id);
90
+
91
+ -- ---------------------------------------------------------------------------
92
+ -- Append-only, for everyone
93
+ -- ---------------------------------------------------------------------------
94
+
95
+ create or replace function audit_log_is_append_only()
96
+ returns trigger
97
+ language plpgsql
98
+ as $$
99
+ begin
100
+ if current_setting('ekwo.audit_purge', true) = 'on' and tg_op = 'DELETE' then
101
+ return old;
102
+ end if;
103
+ raise exception 'audit_log_append_only: the audit trail is written once. % is refused; rows leave it only through purge_audit_log(date).', lower(tg_op);
104
+ end;
105
+ $$;
106
+
107
+ comment on function audit_log_is_append_only() is
108
+ 'Refuses every update and every delete on audit_log, table owner included. purge_audit_log() sets ekwo.audit_purge for its own transaction, which is the one exception.';
109
+
110
+ create trigger audit_log_append_only
111
+ before update or delete on audit_log
112
+ for each row execute function audit_log_is_append_only();
113
+
114
+ -- ---------------------------------------------------------------------------
115
+ -- Writing a row
116
+ --
117
+ -- One function, `security definer`, so the triggers insert regardless of the
118
+ -- policies of the table they hang on and regardless of the fact that
119
+ -- `audit_log` has no insert policy at all. Nothing else may call it: the
120
+ -- grants at the end of this file close it to everyone but the owner.
121
+ -- ---------------------------------------------------------------------------
122
+
123
+ create or replace function audit_record(
124
+ p_company_id uuid,
125
+ p_table text,
126
+ p_record_id uuid,
127
+ p_record_key text,
128
+ p_operation audit_operation,
129
+ p_action text default null,
130
+ p_old jsonb default null,
131
+ p_new jsonb default null
132
+ )
133
+ returns bigint
134
+ language plpgsql
135
+ security definer
136
+ set search_path = public, pg_temp
137
+ as $$
138
+ declare
139
+ v_id bigint;
140
+ begin
141
+ insert into audit_log (actor_id, api_key_id, company_id, table_name, record_id,
142
+ record_key, operation, action, old_values, new_values)
143
+ values (auth.uid(), (select id from current_api_key()), p_company_id, p_table,
144
+ p_record_id, p_record_key, p_operation, p_action, p_old, p_new)
145
+ returning id into v_id;
146
+ return v_id;
147
+ end;
148
+ $$;
149
+
150
+ comment on function audit_record(uuid, text, uuid, text, audit_operation, text, jsonb, jsonb) is
151
+ 'Writes one row of the audit trail. Called by the triggers of this schema and by the functions that perform an act; never by a client.';
152
+
153
+ -- ---------------------------------------------------------------------------
154
+ -- The generic trigger
155
+ --
156
+ -- Configured by one jsonb argument rather than by a row of positional ones,
157
+ -- because a trigger declaration is read far more often than it is written:
158
+ --
159
+ -- company the column holding the company, or absent for reference data of
160
+ -- the installation itself
161
+ -- key the columns that make the natural key, joined by `/`
162
+ -- redact columns whose value is replaced by null — a secret is stored
163
+ -- once, in the table that owns it, and never a second time here
164
+ -- action_insert / action_delete
165
+ -- the name of the act, where an insert or a delete *is* one
166
+ -- ---------------------------------------------------------------------------
167
+
168
+ create or replace function audit_changes()
169
+ returns trigger
170
+ language plpgsql
171
+ security definer
172
+ set search_path = public, pg_temp
173
+ as $$
174
+ declare
175
+ v_config jsonb := coalesce(tg_argv[0], '{}')::jsonb;
176
+ v_old jsonb := case when tg_op = 'INSERT' then null else to_jsonb(old) end;
177
+ v_new jsonb := case when tg_op = 'DELETE' then null else to_jsonb(new) end;
178
+ v_subject jsonb := coalesce(v_new, v_old);
179
+ v_company uuid;
180
+ v_column text;
181
+ v_key text := '';
182
+ v_action text;
183
+ begin
184
+ -- The installation setting itself up. See the head of this file.
185
+ if is_installer() then
186
+ return null;
187
+ end if;
188
+
189
+ -- `updated_at` is the clock, not a change: `occurred_at` on the audit row
190
+ -- already says when. It is dropped from both sides so that an update which
191
+ -- moved nothing else compares equal.
192
+ v_old := v_old - 'updated_at';
193
+ v_new := v_new - 'updated_at';
194
+
195
+ -- An update that changed nothing is not a change. Re-applying an idempotent
196
+ -- seed upserts every row of the reference data; without this, `ekwo migrate`
197
+ -- would write a page of audit rows saying that nothing happened.
198
+ if tg_op = 'UPDATE' and v_old = v_new then
199
+ return null;
200
+ end if;
201
+
202
+ if v_config ? 'company' then
203
+ v_company := nullif(v_subject ->> (v_config ->> 'company'), '')::uuid;
204
+ end if;
205
+
206
+ for v_column in select jsonb_array_elements_text(coalesce(v_config -> 'key', '["id"]'::jsonb)) loop
207
+ v_key := case when v_key = '' then '' else v_key || '/' end
208
+ || coalesce(v_subject ->> v_column, '');
209
+ end loop;
210
+ -- A draft carries no number yet, and a row identified by nothing is a row
211
+ -- nobody can find again.
212
+ if v_key = '' or v_key = '/' then
213
+ v_key := coalesce(v_subject ->> 'id', '(unkeyed)');
214
+ end if;
215
+
216
+ for v_column in select jsonb_array_elements_text(coalesce(v_config -> 'redact', '[]'::jsonb)) loop
217
+ if v_old is not null and v_old ? v_column then v_old := jsonb_set(v_old, array[v_column], 'null'::jsonb); end if;
218
+ if v_new is not null and v_new ? v_column then v_new := jsonb_set(v_new, array[v_column], 'null'::jsonb); end if;
219
+ end loop;
220
+
221
+ v_action := case tg_op
222
+ when 'INSERT' then v_config ->> 'action_insert'
223
+ when 'DELETE' then v_config ->> 'action_delete'
224
+ else null
225
+ end;
226
+
227
+ perform audit_record(
228
+ v_company,
229
+ tg_table_name,
230
+ case when v_subject ? 'id' and (v_subject ->> 'id') ~ '^[0-9a-f]{8}-' then (v_subject ->> 'id')::uuid end,
231
+ v_key,
232
+ lower(tg_op)::audit_operation,
233
+ v_action,
234
+ v_old,
235
+ v_new
236
+ );
237
+ return null;
238
+ end;
239
+ $$;
240
+
241
+ comment on function audit_changes() is
242
+ 'The generic audit trigger. One jsonb argument names the company column, the natural key, the columns to redact and the acts an insert or a delete stands for.';
243
+
244
+ -- ---------------------------------------------------------------------------
245
+ -- The state-change trigger
246
+ --
247
+ -- The act, not the content. A document that is posted, a payment that is
248
+ -- booked, a financial year that closes: what is recorded is the transition and
249
+ -- the few fields that identify the row, never the whole of it.
250
+ --
251
+ -- watch the column whose change is the act
252
+ -- prefix the act is `<prefix>_<new value>`: document_posted, payment_cancelled
253
+ -- true / false
254
+ -- for a boolean column, the name of each direction
255
+ -- fields the columns copied into the payload beside the watched one
256
+ -- ---------------------------------------------------------------------------
257
+
258
+ create or replace function audit_state_change()
259
+ returns trigger
260
+ language plpgsql
261
+ security definer
262
+ set search_path = public, pg_temp
263
+ as $$
264
+ declare
265
+ v_config jsonb := coalesce(tg_argv[0], '{}')::jsonb;
266
+ v_watch text := v_config ->> 'watch';
267
+ v_old jsonb := to_jsonb(old);
268
+ v_new jsonb := to_jsonb(new);
269
+ v_before text := v_old ->> v_watch;
270
+ v_after text := v_new ->> v_watch;
271
+ v_action text;
272
+ v_column text;
273
+ v_payload jsonb := '{}'::jsonb;
274
+ begin
275
+ if v_before is not distinct from v_after then
276
+ return null;
277
+ end if;
278
+
279
+ if v_config ? 'true' then
280
+ v_action := case when v_after = 'true' then v_config ->> 'true' else v_config ->> 'false' end;
281
+ else
282
+ v_action := (v_config ->> 'prefix') || '_' || v_after;
283
+ end if;
284
+
285
+ for v_column in select jsonb_array_elements_text(coalesce(v_config -> 'fields', '[]'::jsonb)) loop
286
+ v_payload := v_payload || jsonb_build_object(v_column, v_new -> v_column);
287
+ end loop;
288
+
289
+ perform audit_record(
290
+ nullif(v_new ->> coalesce(v_config ->> 'company', 'company_id'), '')::uuid,
291
+ tg_table_name,
292
+ (v_new ->> 'id')::uuid,
293
+ coalesce(nullif(v_new ->> coalesce(v_config ->> 'key', 'id'), ''), v_new ->> 'id', '(unkeyed)'),
294
+ 'update',
295
+ v_action,
296
+ jsonb_build_object(v_watch, v_before),
297
+ v_payload || jsonb_build_object(v_watch, v_after)
298
+ );
299
+ return null;
300
+ end;
301
+ $$;
302
+
303
+ comment on function audit_state_change() is
304
+ 'Records the act a state column stands for — a document posted, a payment booked, a year closed — with the fields that identify the row and never the whole of it.';
305
+
306
+ -- ---------------------------------------------------------------------------
307
+ -- Posting an entry, and reversing one
308
+ --
309
+ -- `entries` gets its own function because the ledger has a second act the
310
+ -- others do not: a reversal is an entry that points at the one it undoes, and
311
+ -- calling that "posted" would lose the only word an auditor is looking for.
312
+ -- ---------------------------------------------------------------------------
313
+
314
+ create or replace function audit_entry_posting()
315
+ returns trigger
316
+ language plpgsql
317
+ security definer
318
+ set search_path = public, pg_temp
319
+ as $$
320
+ begin
321
+ if old.state is not distinct from new.state then
322
+ return null;
323
+ end if;
324
+
325
+ perform audit_record(
326
+ new.company_id,
327
+ 'entries',
328
+ new.id,
329
+ coalesce(new.number, new.id::text),
330
+ 'update',
331
+ case
332
+ when new.state = 'posted' and new.reversed_entry_id is not null then 'entry_reversed'
333
+ else 'entry_' || new.state::text
334
+ end,
335
+ jsonb_build_object('state', old.state),
336
+ jsonb_build_object('state', new.state, 'number', new.number,
337
+ 'entry_date', new.entry_date, 'kind', new.kind,
338
+ 'reversed_entry_id', new.reversed_entry_id)
339
+ );
340
+ return null;
341
+ end;
342
+ $$;
343
+
344
+ comment on function audit_entry_posting() is
345
+ 'Records that an entry was posted, cancelled, or posted as the reversal of another. The lines themselves are not audited: a posted entry is immutable and is corrected by a reversal.';
346
+
347
+ -- ---------------------------------------------------------------------------
348
+ -- What is covered
349
+ --
350
+ -- Everything that decides how a future entry is booked, plus who may book it.
351
+ -- ---------------------------------------------------------------------------
352
+
353
+ create trigger accounts_audit after insert or update or delete on accounts
354
+ for each row execute function audit_changes('{"company":"company_id","key":["code"]}');
355
+
356
+ create trigger journals_audit after insert or update or delete on journals
357
+ for each row execute function audit_changes('{"company":"company_id","key":["code"]}');
358
+
359
+ create trigger taxes_audit after insert or update or delete on taxes
360
+ for each row execute function audit_changes('{"company":"company_id","key":["code"]}');
361
+
362
+ create trigger tax_postings_audit after insert or update or delete on tax_postings
363
+ for each row execute function audit_changes('{"company":"company_id","key":["id"]}');
364
+
365
+ create trigger bank_accounts_audit after insert or update or delete on bank_accounts
366
+ for each row execute function audit_changes('{"company":"company_id","key":["id"]}');
367
+
368
+ create trigger contacts_audit after insert or update or delete on contacts
369
+ for each row execute function audit_changes('{"company":"company_id","key":["id"]}');
370
+
371
+ create trigger products_audit after insert or update or delete on products
372
+ for each row execute function audit_changes('{"company":"company_id","key":["code"]}');
373
+
374
+ create trigger companies_audit after insert or update or delete on companies
375
+ for each row execute function audit_changes('{"company":"id","key":["id"]}');
376
+
377
+ create trigger fiscal_years_audit after insert or delete on fiscal_years
378
+ for each row execute function audit_changes('{"company":"company_id","key":["name"]}');
379
+
380
+ create trigger company_members_audit after insert or update or delete on company_members
381
+ for each row execute function audit_changes('{"company":"company_id","key":["user_id"]}');
382
+
383
+ create trigger company_packs_audit after insert or update or delete on company_packs
384
+ for each row execute function audit_changes('{"company":"company_id","key":["country"]}');
385
+
386
+ -- The two tables that hold a secret. Only its hash is stored there, and not
387
+ -- even that is copied here: a hash is a credential that can be attacked
388
+ -- offline, and the audit trail is read by more people than the table is.
389
+ create trigger api_keys_audit after insert or update or delete on api_keys
390
+ for each row execute function audit_changes('{"company":"company_id","key":["prefix"],"redact":["key_hash"]}');
391
+
392
+ create trigger company_invitations_audit after insert or update or delete on company_invitations
393
+ for each row execute function audit_changes('{"company":"company_id","key":["email"],"redact":["token_hash"]}');
394
+
395
+ -- Reference data of the installation: no company, so only an instance
396
+ -- administrator reads these rows back.
397
+ create trigger instance_admins_audit after insert or update or delete on instance_admins
398
+ for each row execute function audit_changes('{"key":["user_id"]}');
399
+
400
+ create trigger country_packs_audit after insert or update or delete on country_packs
401
+ for each row execute function audit_changes('{"key":["country"]}');
402
+
403
+ create trigger country_defaults_audit after insert or update or delete on country_defaults
404
+ for each row execute function audit_changes('{"key":["country"]}');
405
+
406
+ -- ---------------------------------------------------------------------------
407
+ -- The acts
408
+ -- ---------------------------------------------------------------------------
409
+
410
+ create trigger documents_audit_state after update on documents
411
+ for each row execute function audit_state_change(
412
+ '{"watch":"state","prefix":"document","key":"number","fields":["doc_type","document_date","amount_total","entry_id","contact_id"]}');
413
+
414
+ create trigger payments_audit_state after update on payments
415
+ for each row execute function audit_state_change(
416
+ '{"watch":"state","prefix":"payment","fields":["payment_date","amount","entry_id","contact_id"]}');
417
+
418
+ create trigger fiscal_years_audit_close after update on fiscal_years
419
+ for each row execute function audit_state_change(
420
+ '{"watch":"is_closed","true":"fiscal_year_closed","false":"fiscal_year_reopened","key":"name","fields":["start_date","end_date"]}');
421
+
422
+ create trigger entries_audit_posting after update on entries
423
+ for each row execute function audit_entry_posting();
424
+
425
+ -- Matching and unmatching a payment: an insert and a delete that are each an
426
+ -- act, so the generic trigger names them.
427
+ create trigger reconciliations_audit after insert or delete on reconciliations
428
+ for each row execute function audit_changes(
429
+ '{"company":"company_id","key":["id"],"action_insert":"payment_reconciled","action_delete":"payment_unreconciled"}');
430
+
431
+ -- ---------------------------------------------------------------------------
432
+ -- The purge
433
+ --
434
+ -- A retention policy is a legal decision, not a default: nothing in this
435
+ -- schema deletes an audit row on its own. `purge_audit_log` takes the cutoff
436
+ -- it is asked for, deletes what is strictly older, and is reachable only by
437
+ -- `service_role` — the operator of the installation, never a signed-in user
438
+ -- and never a machine key.
439
+ -- ---------------------------------------------------------------------------
440
+
441
+ create or replace function purge_audit_log(p_before date)
442
+ returns bigint
443
+ language plpgsql
444
+ security definer
445
+ set search_path = public, pg_temp
446
+ as $$
447
+ declare
448
+ v_deleted bigint;
449
+ begin
450
+ if p_before is null then
451
+ raise exception 'audit_purge_needs_a_date: name the date before which rows are dropped. There is no default retention.';
452
+ end if;
453
+ if p_before > current_date then
454
+ raise exception 'audit_purge_in_the_future: % is not in the past, so this would empty the trail.', p_before;
455
+ end if;
456
+
457
+ perform set_config('ekwo.audit_purge', 'on', true);
458
+ delete from audit_log where occurred_at < p_before::timestamptz;
459
+ get diagnostics v_deleted = row_count;
460
+ perform set_config('ekwo.audit_purge', '', true);
461
+
462
+ perform audit_record(null, 'audit_log', null, p_before::text, 'delete', 'audit_log_purged',
463
+ null, jsonb_build_object('before', p_before, 'rows', v_deleted));
464
+ return v_deleted;
465
+ end;
466
+ $$;
467
+
468
+ comment on function purge_audit_log(date) is
469
+ 'Drops audit rows older than a date the caller names, and records that it did. service_role only: retention is the operator''s decision and no signed-in user may make it.';
470
+
471
+ -- ---------------------------------------------------------------------------
472
+ -- Row level security
473
+ --
474
+ -- Select only, and there is no other policy on purpose: the trail is written
475
+ -- by `security definer` triggers that run as the owner, so a client has no
476
+ -- reason to hold an insert policy and every reason not to.
477
+ -- ---------------------------------------------------------------------------
478
+
479
+ alter table audit_log enable row level security;
480
+
481
+ create policy audit_log_select on audit_log
482
+ for select using (
483
+ case when company_id is null then is_instance_admin()
484
+ else is_company_member(company_id) or is_instance_admin()
485
+ end
486
+ );
487
+
488
+ comment on policy audit_log_select on audit_log is
489
+ 'Members of the company read its trail; an instance administrator reads that and the rows of the installation itself. Nobody writes, updates or deletes: there is no policy for it, and a trigger refuses it to the owner too.';
490
+
491
+ -- ---------------------------------------------------------------------------
492
+ -- Grants
493
+ --
494
+ -- The rule of `supabase/migrations/README.md`: a migration that adds a
495
+ -- function closes the schema behind it, from PUBLIC and never from `anon`.
496
+ -- Then the two functions that are not the triggers' own get their audience.
497
+ -- ---------------------------------------------------------------------------
498
+
499
+ revoke execute on all functions in schema public from public;
500
+
501
+ revoke execute on function audit_record(uuid, text, uuid, text, audit_operation, text, jsonb, jsonb)
502
+ from public, anon, authenticated;
503
+ revoke execute on function audit_changes() from public, anon, authenticated;
504
+ revoke execute on function audit_state_change() from public, anon, authenticated;
505
+ revoke execute on function audit_entry_posting() from public, anon, authenticated;
506
+ revoke execute on function audit_log_is_append_only() from public, anon, authenticated;
507
+
508
+ revoke execute on function purge_audit_log(date) from public, anon, authenticated;
509
+ grant execute on function purge_audit_log(date) to service_role;