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,187 @@
1
+ /**
2
+ * Profiles: which instance, as whom, for which company — kept between commands.
3
+ *
4
+ * `ekwo.json` is the file of an installation and it is safe to commit, which
5
+ * is why it may never hold a token. What is kept here is the file of a
6
+ * person: it lives in their own configuration directory, outside any
7
+ * repository, and the CLI refuses to write it anywhere else.
8
+ *
9
+ * Two files, because they are not the same kind of thing. `profiles.json`
10
+ * says where each profile points — the instance URL, its publishable key, the
11
+ * address that signed in, the company in use — and holds nothing a dashboard
12
+ * does not already show. `credentials.json` holds the session: an access
13
+ * token that lasts an hour and the refresh token that renews it. Both are
14
+ * written `0600` in a `0700` directory. The password is never written at all:
15
+ * it is sent once, to the instance, and forgotten.
16
+ *
17
+ * The environment is not read here. A CI job sets its variables and never
18
+ * touches this directory; see `identity.ts` for the order.
19
+ */
20
+ import { chmod, mkdir, readFile, rename, stat, writeFile } from 'node:fs/promises';
21
+ import { existsSync } from 'node:fs';
22
+ import { homedir } from 'node:os';
23
+ import { dirname, join, resolve } from 'node:path';
24
+ import { UsageError } from './args.js';
25
+ export const ENV_CONFIG_DIR = 'EKWO_CONFIG_DIR';
26
+ export const ENV_PROFILE = 'EKWO_PROFILE';
27
+ /** The name a first `ekwo login` gives its profile when none is asked for. */
28
+ export const FIRST_PROFILE = 'default';
29
+ const PROFILES_FILE = 'profiles.json';
30
+ const CREDENTIALS_FILE = 'credentials.json';
31
+ /** `EKWO_CONFIG_DIR`, else `$XDG_CONFIG_HOME/ekwo`, else `~/.config/ekwo`. */
32
+ export function configDir(env = process.env) {
33
+ const given = env[ENV_CONFIG_DIR];
34
+ if (given !== undefined && given.trim().length > 0)
35
+ return resolve(given.trim());
36
+ const xdg = env['XDG_CONFIG_HOME'];
37
+ if (xdg !== undefined && xdg.trim().length > 0)
38
+ return join(resolve(xdg.trim()), 'ekwo');
39
+ return join(homedir(), '.config', 'ekwo');
40
+ }
41
+ export function assertProfileName(name) {
42
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(name)) {
43
+ throw new UsageError(`bad_profile_name: "${name}" is not a profile name. Letters, digits, dot, dash and underscore, starting with a letter or a digit.`);
44
+ }
45
+ return name;
46
+ }
47
+ /**
48
+ * Refuses a directory that sits inside a repository.
49
+ *
50
+ * A token in a working tree is one `git add .` away from being published,
51
+ * and nothing about a file called `credentials.json` would stop it. The check
52
+ * is the plain one — a `.git` in the directory or above it — and the way out
53
+ * is named in the refusal.
54
+ */
55
+ export function assertOutsideRepository(dir) {
56
+ let current = resolve(dir);
57
+ for (;;) {
58
+ if (existsSync(join(current, '.git'))) {
59
+ throw new UsageError(`config_dir_in_repository: ${dir} is inside the repository at ${current}, and a session token is never written where a commit could pick it up. Set ${ENV_CONFIG_DIR} to a directory outside any repository.`);
60
+ }
61
+ const parent = dirname(current);
62
+ if (parent === current)
63
+ return;
64
+ current = parent;
65
+ }
66
+ }
67
+ async function readJson(path) {
68
+ try {
69
+ return JSON.parse(await readFile(path, 'utf8'));
70
+ }
71
+ catch (error) {
72
+ if (error.code === 'ENOENT')
73
+ return undefined;
74
+ throw new Error(`unreadable_configuration: ${path} could not be read: ${error.message}`);
75
+ }
76
+ }
77
+ /** Written beside the file and moved over it: a rotated refresh token is never half there. */
78
+ async function writePrivate(dir, file, value) {
79
+ assertOutsideRepository(dir);
80
+ await mkdir(dir, { recursive: true, mode: 0o700 });
81
+ const path = join(dir, file);
82
+ const temporary = `${path}.${process.pid}.tmp`;
83
+ await writeFile(temporary, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
84
+ await chmod(temporary, 0o600);
85
+ await rename(temporary, path);
86
+ }
87
+ function text(value) {
88
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
89
+ }
90
+ function asProfile(raw) {
91
+ if (typeof raw !== 'object' || raw === null)
92
+ return undefined;
93
+ const record = raw;
94
+ const supabaseUrl = text(record['supabase_url']);
95
+ const anonKey = text(record['anon_key']);
96
+ if (supabaseUrl === undefined || anonKey === undefined)
97
+ return undefined;
98
+ const company = record['company'];
99
+ const companyId = text(company?.['id']);
100
+ const companyName = text(company?.['name']);
101
+ const email = text(record['email']);
102
+ const userId = text(record['user_id']);
103
+ return {
104
+ supabase_url: supabaseUrl,
105
+ anon_key: anonKey,
106
+ ...(email === undefined ? {} : { email }),
107
+ ...(userId === undefined ? {} : { user_id: userId }),
108
+ ...(companyId === undefined || companyName === undefined
109
+ ? {}
110
+ : { company: { id: companyId, name: companyName } }),
111
+ };
112
+ }
113
+ export async function readProfiles(dir) {
114
+ const raw = (await readJson(join(dir, PROFILES_FILE)));
115
+ const profiles = {};
116
+ const listed = raw?.['profiles'];
117
+ if (typeof listed === 'object' && listed !== null) {
118
+ for (const [name, value] of Object.entries(listed)) {
119
+ const profile = asProfile(value);
120
+ if (profile !== undefined)
121
+ profiles[name] = profile;
122
+ }
123
+ }
124
+ const current = text(raw?.['current']);
125
+ return { ...(current === undefined ? {} : { current }), profiles };
126
+ }
127
+ export async function writeProfiles(dir, file) {
128
+ await writePrivate(dir, PROFILES_FILE, {
129
+ $comment: 'Where each profile of the ekwo command line points. No token lives here; the session is in credentials.json, beside this file.',
130
+ ...(file.current === undefined ? {} : { current: file.current }),
131
+ profiles: file.profiles,
132
+ });
133
+ }
134
+ function asSession(raw) {
135
+ if (typeof raw !== 'object' || raw === null)
136
+ return undefined;
137
+ const record = raw;
138
+ const accessToken = text(record['access_token']);
139
+ const refreshToken = text(record['refresh_token']);
140
+ const expiresAt = record['expires_at'];
141
+ if (accessToken === undefined || refreshToken === undefined || typeof expiresAt !== 'number') {
142
+ return undefined;
143
+ }
144
+ return { access_token: accessToken, refresh_token: refreshToken, expires_at: expiresAt };
145
+ }
146
+ async function readCredentials(dir) {
147
+ const raw = await readJson(join(dir, CREDENTIALS_FILE));
148
+ const sessions = {};
149
+ if (typeof raw === 'object' && raw !== null) {
150
+ for (const [name, value] of Object.entries(raw)) {
151
+ const session = asSession(value);
152
+ if (session !== undefined)
153
+ sessions[name] = session;
154
+ }
155
+ }
156
+ return sessions;
157
+ }
158
+ export async function readSession(dir, profile) {
159
+ return (await readCredentials(dir))[profile];
160
+ }
161
+ export async function writeSession(dir, profile, session) {
162
+ const sessions = await readCredentials(dir);
163
+ sessions[profile] = session;
164
+ await writePrivate(dir, CREDENTIALS_FILE, sessions);
165
+ }
166
+ /** True when there was a session to forget. */
167
+ export async function forgetSession(dir, profile) {
168
+ const sessions = await readCredentials(dir);
169
+ if (sessions[profile] === undefined)
170
+ return false;
171
+ delete sessions[profile];
172
+ await writePrivate(dir, CREDENTIALS_FILE, sessions);
173
+ return true;
174
+ }
175
+ /** True when somebody other than the owner can read the session file. */
176
+ export async function credentialsAreExposed(dir) {
177
+ if (process.platform === 'win32')
178
+ return false;
179
+ try {
180
+ const info = await stat(join(dir, CREDENTIALS_FILE));
181
+ return (info.mode & 0o077) !== 0;
182
+ }
183
+ catch {
184
+ return false;
185
+ }
186
+ }
187
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../src/profiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Asking questions, on `node:readline` alone.
3
+ *
4
+ * A masked prompt is the reason this is written out rather than installed:
5
+ * the database password and the service_role key pass through it, and the
6
+ * fewer packages that can see them the better. Node has everything needed —
7
+ * the masking trick is a writable stream that drops what readline echoes.
8
+ */
9
+ /**
10
+ * Whether there is somebody to ask.
11
+ *
12
+ * Both ends have to be a terminal, and `--json` means there is nobody: the
13
+ * standard output is promised to one JSON document, and the caller that asked
14
+ * for it is a program that would wait on a question for ever.
15
+ */
16
+ export declare function isInteractive(): boolean;
17
+ /** Thrown when a question has to be asked and there is nobody to answer it. */
18
+ export declare class NotInteractiveError extends Error {
19
+ constructor(what: string, flag: string);
20
+ }
21
+ /** A free-text question. `defaultValue` is offered in brackets and accepted on Enter. */
22
+ export declare function ask(question: string, defaultValue?: string): Promise<string>;
23
+ /** Keeps asking until the answer is not empty. */
24
+ export declare function askRequired(question: string, defaultValue?: string): Promise<string>;
25
+ /** A question whose answer is not echoed. */
26
+ export declare function askSecret(question: string): Promise<string>;
27
+ /** A yes/no question. The default is what Enter means. */
28
+ export declare function confirm(question: string, defaultValue?: boolean): Promise<boolean>;
29
+ /**
30
+ * One of a short list. Returns the chosen value, not its index.
31
+ *
32
+ * `defaultValue` is optional on purpose: a question whose answer decides what
33
+ * the books are — the country — has no right answer to preselect, and Enter
34
+ * on it would be a choice nobody made.
35
+ */
36
+ export declare function choose(question: string, options: {
37
+ value: string;
38
+ label: string;
39
+ }[], defaultValue?: string): Promise<string>;
40
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;GAMG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAeD,+EAA+E;AAC/E,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAMvC;AASD,yFAAyF;AACzF,wBAAsB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAYlF;AAED,kDAAkD;AAClD,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAM1F;AAgBD,6CAA6C;AAC7C,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAcjE;AAED,0DAA0D;AAC1D,wBAAsB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,UAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAKtF;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,EAC3C,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAQjB"}
package/dist/prompt.js ADDED
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Asking questions, on `node:readline` alone.
3
+ *
4
+ * A masked prompt is the reason this is written out rather than installed:
5
+ * the database password and the service_role key pass through it, and the
6
+ * fewer packages that can see them the better. Node has everything needed —
7
+ * the masking trick is a writable stream that drops what readline echoes.
8
+ */
9
+ import { createInterface } from 'node:readline';
10
+ import { Writable } from 'node:stream';
11
+ import { cyan, dim, isJsonMode } from './ui.js';
12
+ /**
13
+ * Whether there is somebody to ask.
14
+ *
15
+ * Both ends have to be a terminal, and `--json` means there is nobody: the
16
+ * standard output is promised to one JSON document, and the caller that asked
17
+ * for it is a program that would wait on a question for ever.
18
+ */
19
+ export function isInteractive() {
20
+ return process.stdin.isTTY === true && process.stdout.isTTY === true && !isJsonMode();
21
+ }
22
+ /**
23
+ * The last line of defence, under every question this file can ask.
24
+ *
25
+ * Each command already decides whether it may ask and says which flag was
26
+ * missing when it may not. This is for the day one of them forgets: a question
27
+ * put to a pipe does not fail, it waits, and an agent driving a shell has no
28
+ * way to tell a wait from work. So a prompt that is reached with nobody to
29
+ * answer stops the command instead, with the exit code of a wrong call.
30
+ */
31
+ function refuseToBlock(question) {
32
+ if (!isInteractive())
33
+ throw new NotInteractiveError(`an answer to "${question}"`, 'the matching flag');
34
+ }
35
+ /** Thrown when a question has to be asked and there is nobody to answer it. */
36
+ export class NotInteractiveError extends Error {
37
+ constructor(what, flag) {
38
+ super(`missing_input: ${what} was not given and this is not a terminal. ` +
39
+ `Pass ${flag}, or set the matching environment variable.`);
40
+ }
41
+ }
42
+ function withInterface(fn) {
43
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
44
+ return fn(rl).finally(() => {
45
+ rl.close();
46
+ });
47
+ }
48
+ /** A free-text question. `defaultValue` is offered in brackets and accepted on Enter. */
49
+ export async function ask(question, defaultValue) {
50
+ refuseToBlock(question);
51
+ const suffix = defaultValue !== undefined ? dim(` [${defaultValue}]`) : '';
52
+ const answer = await withInterface((rl) => new Promise((resolve) => {
53
+ rl.question(`${cyan('?')} ${question}${suffix} `, resolve);
54
+ }));
55
+ const trimmed = answer.trim();
56
+ if (trimmed.length > 0)
57
+ return trimmed;
58
+ return defaultValue ?? '';
59
+ }
60
+ /** Keeps asking until the answer is not empty. */
61
+ export async function askRequired(question, defaultValue) {
62
+ for (;;) {
63
+ const answer = await ask(question, defaultValue);
64
+ if (answer.length > 0)
65
+ return answer;
66
+ process.stdout.write(` ${dim('An answer is needed.')}\n`);
67
+ }
68
+ }
69
+ /** A stream that forwards to stdout until it is muted, then swallows. */
70
+ class MutableOutput extends Writable {
71
+ muted = false;
72
+ _write(chunk, _encoding, callback) {
73
+ if (!this.muted)
74
+ process.stdout.write(chunk);
75
+ callback();
76
+ }
77
+ }
78
+ /** A question whose answer is not echoed. */
79
+ export async function askSecret(question) {
80
+ refuseToBlock(question);
81
+ const output = new MutableOutput();
82
+ const rl = createInterface({ input: process.stdin, output, terminal: true });
83
+ try {
84
+ const answer = await new Promise((resolve) => {
85
+ rl.question(`${cyan('?')} ${question} `, resolve);
86
+ output.muted = true;
87
+ });
88
+ process.stdout.write('\n');
89
+ return answer.trim();
90
+ }
91
+ finally {
92
+ rl.close();
93
+ }
94
+ }
95
+ /** A yes/no question. The default is what Enter means. */
96
+ export async function confirm(question, defaultValue = false) {
97
+ const hint = defaultValue ? 'Y/n' : 'y/N';
98
+ const answer = (await ask(`${question} ${dim(`(${hint})`)}`)).toLowerCase();
99
+ if (answer.length === 0)
100
+ return defaultValue;
101
+ return answer === 'y' || answer === 'yes';
102
+ }
103
+ /**
104
+ * One of a short list. Returns the chosen value, not its index.
105
+ *
106
+ * `defaultValue` is optional on purpose: a question whose answer decides what
107
+ * the books are — the country — has no right answer to preselect, and Enter
108
+ * on it would be a choice nobody made.
109
+ */
110
+ export async function choose(question, options, defaultValue) {
111
+ const labels = options.map((o) => `${o.value} (${o.label})`).join(', ');
112
+ for (;;) {
113
+ const answer = (await ask(`${question} ${dim(labels)}`, defaultValue)).toUpperCase();
114
+ const match = options.find((o) => o.value.toUpperCase() === answer);
115
+ if (match !== undefined)
116
+ return match.value;
117
+ process.stdout.write(` ${dim(`Choose one of: ${options.map((o) => o.value).join(', ')}`)}\n`);
118
+ }
119
+ }
120
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Registering an installation with Ekwo.
3
+ *
4
+ * This is an opt-in, asked once at the end of `ekwo init`, and the default
5
+ * answer is no. Community works unregistered, forever: nothing in the schema
6
+ * and nothing in this CLI reads `contact_email` or `registered_at` to decide
7
+ * what you may do. The only thing registration buys is that somebody can tell
8
+ * you a security advisory concerns your version.
9
+ *
10
+ * Two halves, deliberately independent:
11
+ *
12
+ * - **In your database.** `register_instance(email)` writes the address and
13
+ * a date onto the instance row. `unregister_instance()` clears both.
14
+ * - **At Ekwo.** A POST to `EKWO_REGISTRY_URL`. The endpoint does not exist
15
+ * yet, and that is fine: the local half stands on its own, a failed POST
16
+ * is a soft message rather than an error, and `ekwo register` retries.
17
+ *
18
+ * The payload carries what an advisory needs to be addressed — the locally
19
+ * generated `instance_id`, the organisation, the country, the edition, the
20
+ * schema version, and the address given. No ledger data, no user list, no
21
+ * connection string, ever.
22
+ */
23
+ import type { FetchLike } from './auth.js';
24
+ import type { SqlClient } from './sql.js';
25
+ export declare const DEFAULT_REGISTRY_URL = "https://api.ekwo.ai/v1/registrations";
26
+ export declare function registryUrl(env?: NodeJS.ProcessEnv): string;
27
+ export interface InstanceRow {
28
+ instance_id: string;
29
+ organization_name: string;
30
+ country: string;
31
+ edition: string;
32
+ schema_version: string;
33
+ contact_email: string | null;
34
+ registered_at: string | null;
35
+ }
36
+ export declare function readInstance(db: SqlClient): Promise<InstanceRow | undefined>;
37
+ export interface RegistrationPayload {
38
+ instance_id: string;
39
+ organization: string;
40
+ country: string;
41
+ edition: string;
42
+ schema_version: string;
43
+ contact_email: string;
44
+ }
45
+ export declare function payloadFor(instance: InstanceRow, email: string): RegistrationPayload;
46
+ export interface RegisterResult {
47
+ /** The instance row was written: this always happens. */
48
+ recordedLocally: boolean;
49
+ /** The POST reached Ekwo. False is a supported, non-fatal state. */
50
+ announced: boolean;
51
+ /** Why the POST did not land, when it did not. */
52
+ reason?: string;
53
+ payload: RegistrationPayload;
54
+ }
55
+ export interface RegisterOptions {
56
+ /** The administrator whose authority `register_instance()` checks. */
57
+ adminUserId: string;
58
+ email: string;
59
+ organization?: string | undefined;
60
+ country?: string | undefined;
61
+ url?: string;
62
+ fetchImpl?: FetchLike;
63
+ }
64
+ /**
65
+ * Records the registration locally, then tries to announce it.
66
+ *
67
+ * The local write comes first on purpose. If the network is down, or the
68
+ * endpoint is not live yet, the installation still knows it opted in and
69
+ * `ekwo register` can send it later.
70
+ */
71
+ export declare function register(db: SqlClient, options: RegisterOptions): Promise<RegisterResult>;
72
+ /** POSTs the payload. Never throws: a failure here is not a failed install. */
73
+ export declare function announce(payload: RegistrationPayload, options?: {
74
+ url?: string;
75
+ fetchImpl?: FetchLike;
76
+ }): Promise<{
77
+ announced: boolean;
78
+ reason?: string;
79
+ }>;
80
+ /** Clears the address and the date. The local row is the only thing we hold. */
81
+ export declare function unregister(db: SqlClient, adminUserId: string): Promise<InstanceRow | undefined>;
82
+ /** The administrator this CLI acts for: the first one on the installation. */
83
+ export declare function anyAdminId(db: SqlClient): Promise<string | undefined>;
84
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,eAAO,MAAM,oBAAoB,yCAAyC,CAAC;AAE3E,wBAAgB,WAAW,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAGxE;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAOlF;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,mBAAmB,CASpF;AAED,MAAM,WAAW,cAAc;IAC7B,yDAAyD;IACzD,eAAe,EAAE,OAAO,CAAC;IACzB,oEAAoE;IACpE,SAAS,EAAE,OAAO,CAAC;IACnB,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,EAAE,EAAE,SAAS,EACb,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAyBzB;AAED,+EAA+E;AAC/E,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAAO,GACpD,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAclD;AAED,gFAAgF;AAChF,wBAAsB,UAAU,CAC9B,EAAE,EAAE,SAAS,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAKlC;AAED,8EAA8E;AAC9E,wBAAsB,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAM3E"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Registering an installation with Ekwo.
3
+ *
4
+ * This is an opt-in, asked once at the end of `ekwo init`, and the default
5
+ * answer is no. Community works unregistered, forever: nothing in the schema
6
+ * and nothing in this CLI reads `contact_email` or `registered_at` to decide
7
+ * what you may do. The only thing registration buys is that somebody can tell
8
+ * you a security advisory concerns your version.
9
+ *
10
+ * Two halves, deliberately independent:
11
+ *
12
+ * - **In your database.** `register_instance(email)` writes the address and
13
+ * a date onto the instance row. `unregister_instance()` clears both.
14
+ * - **At Ekwo.** A POST to `EKWO_REGISTRY_URL`. The endpoint does not exist
15
+ * yet, and that is fine: the local half stands on its own, a failed POST
16
+ * is a soft message rather than an error, and `ekwo register` retries.
17
+ *
18
+ * The payload carries what an advisory needs to be addressed — the locally
19
+ * generated `instance_id`, the organisation, the country, the edition, the
20
+ * schema version, and the address given. No ledger data, no user list, no
21
+ * connection string, ever.
22
+ */
23
+ import { asUser, first } from './sql.js';
24
+ export const DEFAULT_REGISTRY_URL = 'https://api.ekwo.ai/v1/registrations';
25
+ export function registryUrl(env = process.env) {
26
+ const configured = env['EKWO_REGISTRY_URL'];
27
+ return configured !== undefined && configured.length > 0 ? configured : DEFAULT_REGISTRY_URL;
28
+ }
29
+ export async function readInstance(db) {
30
+ return first(db, `select instance_id, organization_name, country, edition, schema_version,
31
+ contact_email, registered_at
32
+ from instance where id = 1`);
33
+ }
34
+ export function payloadFor(instance, email) {
35
+ return {
36
+ instance_id: instance.instance_id,
37
+ organization: instance.organization_name,
38
+ country: instance.country,
39
+ edition: instance.edition,
40
+ schema_version: instance.schema_version,
41
+ contact_email: email,
42
+ };
43
+ }
44
+ /**
45
+ * Records the registration locally, then tries to announce it.
46
+ *
47
+ * The local write comes first on purpose. If the network is down, or the
48
+ * endpoint is not live yet, the installation still knows it opted in and
49
+ * `ekwo register` can send it later.
50
+ */
51
+ export async function register(db, options) {
52
+ const { adminUserId, email } = options;
53
+ // Optional corrections collected at the same prompt.
54
+ if (options.organization !== undefined && options.organization.length > 0) {
55
+ await db.query('update instance set organization_name = $1 where id = 1', [
56
+ options.organization,
57
+ ]);
58
+ }
59
+ if (options.country !== undefined && options.country.length === 2) {
60
+ await db.query('update instance set country = $1 where id = 1', [
61
+ options.country.toUpperCase(),
62
+ ]);
63
+ }
64
+ await asUser(db, adminUserId, async () => {
65
+ await db.query('select register_instance($1)', [email]);
66
+ });
67
+ const instance = await readInstance(db);
68
+ if (instance === undefined)
69
+ throw new Error('instance_not_initialised: call ekwo init first');
70
+ const payload = payloadFor(instance, email);
71
+ const announced = await announce(payload, options);
72
+ return { recordedLocally: true, payload, ...announced };
73
+ }
74
+ /** POSTs the payload. Never throws: a failure here is not a failed install. */
75
+ export async function announce(payload, options = {}) {
76
+ const url = options.url ?? registryUrl();
77
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
78
+ try {
79
+ const response = await fetchImpl(url, {
80
+ method: 'POST',
81
+ headers: { 'Content-Type': 'application/json' },
82
+ body: JSON.stringify(payload),
83
+ });
84
+ if (response.ok)
85
+ return { announced: true };
86
+ return { announced: false, reason: `the registry answered HTTP ${response.status}` };
87
+ }
88
+ catch (error) {
89
+ return { announced: false, reason: error.message };
90
+ }
91
+ }
92
+ /** Clears the address and the date. The local row is the only thing we hold. */
93
+ export async function unregister(db, adminUserId) {
94
+ await asUser(db, adminUserId, async () => {
95
+ await db.query('select unregister_instance()');
96
+ });
97
+ return readInstance(db);
98
+ }
99
+ /** The administrator this CLI acts for: the first one on the installation. */
100
+ export async function anyAdminId(db) {
101
+ const row = await first(db, 'select user_id from instance_admins order by created_at limit 1');
102
+ return row?.user_id;
103
+ }
104
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
package/dist/rest.d.ts ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Talking to an instance as a person: PostgREST, with that person's token.
3
+ *
4
+ * Everything a bookkeeping command does goes through here, and nothing here
5
+ * holds a privilege: the `apikey` is the publishable one, the bearer is the
6
+ * session of whoever signed in, and row level security decides the rest —
7
+ * exactly as it does for the MCP server, which calls the same functions.
8
+ *
9
+ * **A refusal keeps its SQLSTATE over this route.** PostgREST answers an error
10
+ * of the database with the fields Postgres gave it — `code`, `message`,
11
+ * `details`, `hint` — so the error thrown here carries `code`, `detail` and
12
+ * `hint` the way both SQL drivers do, and `output.ts` reads a locked period
13
+ * off it as exit code 3 without knowing which route it came over. An error of
14
+ * PostgREST's own is `PGRST…`, which is not an SQLSTATE and stays a failure.
15
+ *
16
+ * **A token that stopped working is renewed once, and the call is made
17
+ * again.** An access token lasts an hour and a terminal stays open for a day.
18
+ * It is renewed ahead of time when it is about to lapse, and after the fact
19
+ * when the instance answers 401 anyway — a clock that drifted, a session the
20
+ * instance ended early. The renewed session is handed to whoever keeps it;
21
+ * a session that cannot be renewed is `session_expired`, never a retry loop.
22
+ */
23
+ import type { Backend } from '@ekwo-ai/core';
24
+ import type { StoredSession } from './profiles.js';
25
+ import { type FetchLike, type Instance, type SessionUser } from './session.js';
26
+ export interface UserClientOptions {
27
+ instance: Instance;
28
+ fetchImpl: FetchLike;
29
+ accessToken: string;
30
+ /** Absent when the token was handed over by the environment: nothing to renew it with. */
31
+ refreshToken?: string | undefined;
32
+ expiresAt?: number | undefined;
33
+ /** Called with the rotated session, before the call that needed it is retried. */
34
+ onRenewed?: ((session: StoredSession) => Promise<void>) | undefined;
35
+ /** What to tell somebody whose session is over. */
36
+ signInAgain: string;
37
+ now?: (() => number) | undefined;
38
+ }
39
+ export interface SelectOptions {
40
+ columns: readonly string[];
41
+ order?: string;
42
+ }
43
+ /** What the database, or PostgREST in front of it, answered. Shaped like a driver error. */
44
+ export declare class RestError extends Error {
45
+ code: string | undefined;
46
+ detail: string | undefined;
47
+ hint: string | undefined;
48
+ constructor(message: string, fields: {
49
+ code?: string | undefined;
50
+ detail?: string | undefined;
51
+ hint?: string | undefined;
52
+ });
53
+ }
54
+ export declare class UserClient {
55
+ private readonly options;
56
+ private accessToken;
57
+ private refreshToken;
58
+ private expiresAt;
59
+ constructor(options: UserClientOptions);
60
+ get instance(): Instance;
61
+ private now;
62
+ private expired;
63
+ private renew;
64
+ /** One request as the user; renewed and made again, once, on a 401. */
65
+ private request;
66
+ private answer;
67
+ /** Calls a function of the schema. Rows, whatever the function returns. */
68
+ rpc<T>(fn: string, args?: Record<string, unknown>): Promise<T[]>;
69
+ /** Reads what the policies let this person see of a table. */
70
+ select<T>(table: string, options: SelectOptions): Promise<T[]>;
71
+ /** Who the instance says this token is. Also the cheapest way to learn it stopped working. */
72
+ user(): Promise<SessionUser>;
73
+ token(): string;
74
+ /**
75
+ * This client as the `Backend` the bookkeeping functions of the core are
76
+ * written against — the interface the MCP server implements over
77
+ * `@supabase/supabase-js`. Same five operations, same functions on top.
78
+ */
79
+ backend(actingAs: string | undefined): Backend;
80
+ }
81
+ //# sourceMappingURL=rest.d.ts.map