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.
- package/README.md +873 -0
- package/dist/args.d.ts +57 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +134 -0
- package/dist/args.js.map +1 -0
- package/dist/assets/expected-objects.json +9432 -0
- package/dist/assets/migrations/20260911120000_core_companies.sql +260 -0
- package/dist/assets/migrations/20260911120100_accounts_journals.sql +211 -0
- package/dist/assets/migrations/20260911120200_contacts.sql +90 -0
- package/dist/assets/migrations/20260911120300_taxes.sql +146 -0
- package/dist/assets/migrations/20260911120400_entries.sql +338 -0
- package/dist/assets/migrations/20260911120500_documents.sql +279 -0
- package/dist/assets/migrations/20260911120600_payments_reconciliation.sql +251 -0
- package/dist/assets/migrations/20260911120700_bank.sql +178 -0
- package/dist/assets/migrations/20260911120800_analytics_attachments.sql +128 -0
- package/dist/assets/migrations/20260911120900_post_document.sql +279 -0
- package/dist/assets/migrations/20260911121000_reporting.sql +235 -0
- package/dist/assets/migrations/20260911121100_country_templates.sql +226 -0
- package/dist/assets/migrations/20260911121200_fec.sql +71 -0
- package/dist/assets/migrations/20260911130000_instance.sql +77 -0
- package/dist/assets/migrations/20260911130100_instance_members.sql +224 -0
- package/dist/assets/migrations/20260911140000_instance_admins.sql +112 -0
- package/dist/assets/migrations/20260911160000_tax_posting_templates_unique.sql +17 -0
- package/dist/assets/migrations/20260911170000_document_amount_paid.sql +82 -0
- package/dist/assets/migrations/20260911173000_post_payment.sql +122 -0
- package/dist/assets/migrations/20260911173100_sequence_counters_under_rls.sql +84 -0
- package/dist/assets/migrations/20260911183000_country_journal_defaults.sql +143 -0
- package/dist/assets/migrations/20260911193853_line_account_defaults.sql +274 -0
- package/dist/assets/migrations/20260911195054_products.sql +221 -0
- package/dist/assets/migrations/20260911210131_anon_surface.sql +85 -0
- package/dist/assets/migrations/20260912074712_country_packs.sql +318 -0
- package/dist/assets/migrations/20260912080311_report_code_and_region.sql +198 -0
- package/dist/assets/migrations/20260912081014_pack_certification_maintained.sql +31 -0
- package/dist/assets/migrations/20260912081015_pack_certification_backfill.sql +16 -0
- package/dist/assets/migrations/20260912090407_tax_report_boxes.sql +329 -0
- package/dist/assets/migrations/20260912091917_tax_on_base_value.sql +25 -0
- package/dist/assets/migrations/20260912091918_tax_engine_columns.sql +776 -0
- package/dist/assets/migrations/20260912094412_opening_and_closing.sql +759 -0
- package/dist/assets/migrations/20260912095825_charts_of_accounts.sql +326 -0
- package/dist/assets/migrations/20260912100412_financial_statements.sql +632 -0
- package/dist/assets/migrations/20260912104719_one_formula_evaluator.sql +209 -0
- package/dist/assets/migrations/20260912105720_entry_kind_appropriation.sql +26 -0
- package/dist/assets/migrations/20260912105721_appropriation_entry_kind.sql +444 -0
- package/dist/assets/migrations/20260912111751_document_rules.sql +274 -0
- package/dist/assets/migrations/20260912112132_cash_basis_vat_and_fx.sql +1189 -0
- package/dist/assets/migrations/20260913074512_modules.sql +493 -0
- package/dist/assets/migrations/20260913075903_asset_disposal_roles.sql +47 -0
- package/dist/assets/migrations/20260913083216_capabilities.sql +637 -0
- package/dist/assets/migrations/20260913083901_company_invitations.sql +262 -0
- package/dist/assets/migrations/20260913084402_user_preferences.sql +376 -0
- package/dist/assets/migrations/20260913084847_company_profile.sql +261 -0
- package/dist/assets/migrations/20260913085436_numbering_reads_the_pack.sql +235 -0
- package/dist/assets/migrations/20260913085932_api_keys.sql +303 -0
- package/dist/assets/migrations/20260913090216_fiscal_year_bounds.sql +159 -0
- package/dist/assets/migrations/20260913092527_entries_import.sql +219 -0
- package/dist/assets/migrations/20260913101536_null_safe_guards.sql +188 -0
- package/dist/assets/migrations/20260913102115_installer_is_named.sql +462 -0
- package/dist/assets/migrations/20260913102758_no_currency_default.sql +138 -0
- package/dist/assets/migrations/20260913103355_cash_basis_needs_a_box.sql +453 -0
- package/dist/assets/migrations/20260913104014_aged_balance_named_group.sql +79 -0
- package/dist/assets/migrations/20260913104232_foreign_key_indexes.sql +144 -0
- package/dist/assets/migrations/20260913105120_declared_no_reader.sql +41 -0
- package/dist/assets/migrations/20260913111407_pack_languages.sql +223 -0
- package/dist/assets/migrations/20260913112233_schema_comments_for_a_reader.sql +27 -0
- package/dist/assets/migrations/20260913114535_fec_opening_balances.sql +307 -0
- package/dist/assets/migrations/20260914103412_audit_log.sql +509 -0
- package/dist/assets/migrations/20260914111907_pack_upgrade.sql +428 -0
- package/dist/assets/migrations/20260914120500_rounding_reads_the_currency.sql +206 -0
- package/dist/assets/migrations/20260914121200_amounts_round_at_the_currency.sql +2403 -0
- package/dist/assets/migrations/20260914134325_schema_version_0_2_0.sql +36 -0
- package/dist/assets/migrations/20260914143915_accounts_in_use.sql +428 -0
- package/dist/assets/migrations/20260914144731_account_code_frozen.sql +99 -0
- package/dist/assets/migrations/20260914151207_schema_grants_its_own_rights.sql +284 -0
- package/dist/assets/migrations/20260914152840_pack_upgrade_records_its_own_line.sql +237 -0
- package/dist/assets/migrations/20260914163943_declaration_periodicity.sql +349 -0
- package/dist/assets/migrations/20260915094000_foreign_services_received.sql +37 -0
- package/dist/assets/migrations/20260915094500_mentions_read_a_foreign_service.sql +72 -0
- package/dist/assets/migrations/20260915153000_document_shares.sql +568 -0
- package/dist/assets/migrations/20260915160000_ec_sales_list.sql +181 -0
- package/dist/assets/migrations/20260915161842_pack_sources.sql +56 -0
- package/dist/assets/migrations/20260915170500_schema_version_0_3_0.sql +45 -0
- package/dist/assets/migrations/20260915174500_a_vat_category_is_a_code.sql +177 -0
- package/dist/assets/migrations/20260915180000_document_rule_references.sql +85 -0
- package/dist/assets/migrations/20260915181000_territories.sql +342 -0
- package/dist/assets/migrations/20260915181500_ec_sales_list_reads_the_territories.sql +222 -0
- package/dist/assets/migrations/20260915182000_intracom_triangular.sql +53 -0
- package/dist/assets/migrations/20260915182500_a_triangular_supply_says_reverse_charge.sql +99 -0
- package/dist/assets/migrations/20260915191200_a_document_knows_its_language.sql +633 -0
- package/dist/assets/migrations/20260915195000_a_price_that_holds_its_tax.sql +649 -0
- package/dist/assets/migrations/20260915200000_a_posting_names_its_boxes.sql +1004 -0
- package/dist/assets/migrations/20260916094500_a_company_files_more_than_one_declaration.sql +795 -0
- package/dist/assets/migrations/20260916103000_a_ledger_line_names_its_posting.sql +902 -0
- package/dist/assets/migrations/20260916123000_a_vocabulary_for_a_tax_that_is_not_a_vat.sql +144 -0
- package/dist/assets/migrations/20260916124000_a_box_can_be_a_rate_of_a_box.sql +525 -0
- package/dist/assets/migrations/20260916125000_a_tax_follows_the_territory.sql +1318 -0
- package/dist/assets/migrations/20260916126000_a_tax_point_and_its_exception.sql +1211 -0
- package/dist/assets/migrations/20260917090000_a_counterparty_that_learns.sql +561 -0
- package/dist/assets/migrations/20260917120000_what_the_money_pays.sql +545 -0
- package/dist/assets/migrations/20260917150000_a_filing_is_a_row.sql +488 -0
- package/dist/assets/migrations/20260917170000_when_it_is_due.sql +194 -0
- package/dist/assets/migrations/20260917180000_a_box_is_a_number_and_a_kind.sql +213 -0
- package/dist/assets/migrations/20260917190000_what_a_declaration_owes.sql +486 -0
- package/dist/assets/migrations/20260917200000_what_moved_after_it_went.sql +227 -0
- package/dist/assets/migrations/20260918090000_a_form_names_its_file.sql +27 -0
- package/dist/assets/migrations/20260918110000_a_deposit_and_what_came_back.sql +286 -0
- package/dist/assets/migrations/20260918113741_a_fourth_preset_is_named.sql +9 -0
- package/dist/assets/migrations/20260918113807_a_client_reads_and_hands_over.sql +96 -0
- package/dist/assets/migrations/20260918114322_two_definer_functions_check_their_caller.sql +75 -0
- package/dist/assets/migrations/20260918130000_every_company_somebody_keeps.sql +177 -0
- package/dist/assets/migrations/20260918140000_a_session_nobody_prepared.sql +40 -0
- package/dist/assets/migrations/20260918141107_a_line_keeps_the_tax_it_was_posted_with.sql +256 -0
- package/dist/assets/migrations/20260918141342_a_company_has_an_electronic_address.sql +66 -0
- package/dist/assets/migrations/20260918141605_an_invoice_reads_whole_from_the_views.sql +313 -0
- package/dist/assets/migrations/20260918141627_a_policy_asks_once.sql +132 -0
- package/dist/assets/migrations/20260918143352_a_suggestion_reads_the_words_once.sql +204 -0
- package/dist/assets/migrations/20260918143417_a_reference_of_the_caller_and_a_rehearsal.sql +115 -0
- package/dist/assets/migrations/20260918150712_a_company_leaves_with_its_books.sql +1119 -0
- package/dist/assets/migrations/20260918150931_a_statement_is_imported_once.sql +654 -0
- package/dist/assets/migrations/20260918161204_a_posted_document_does_not_move.sql +437 -0
- package/dist/assets/migrations/20260918161538_a_posted_entry_does_not_move.sql +252 -0
- package/dist/assets/migrations/20260918171946_an_entry_is_posted_by_post_entry.sql +289 -0
- package/dist/assets/migrations/20260918174312_schema_version_0_4_0.sql +53 -0
- package/dist/assets/modules/assets/module.json +13 -0
- package/dist/assets/modules/assets/supabase/migrations/20260913081447_assets.sql +1190 -0
- package/dist/assets/modules/assets/supabase/migrations/20260913104234_foreign_key_indexes.sql +47 -0
- package/dist/assets/modules/assets/supabase/migrations/20260913104500_assets_capabilities.sql +145 -0
- package/dist/assets/modules/assets/supabase/migrations/20260914122100_assets_round_at_the_currency.sql +564 -0
- package/dist/assets/modules/assets/supabase/migrations/20260914145012_assets_accounts_in_use.sql +37 -0
- package/dist/assets/modules/assets/supabase/migrations/20260914151530_assets_grants_its_own_rights.sql +63 -0
- package/dist/assets/modules/assets/supabase/migrations/20260918113912_assets_client_reads.sql +20 -0
- package/dist/assets/modules/assets/supabase/migrations/20260918150801_assets_leave_with_the_company.sql +41 -0
- package/dist/assets/modules/budgets/module.json +12 -0
- package/dist/assets/modules/budgets/supabase/migrations/20260913083012_budgets.sql +210 -0
- package/dist/assets/modules/budgets/supabase/migrations/20260913104233_foreign_key_indexes.sql +37 -0
- package/dist/assets/modules/budgets/supabase/migrations/20260913104501_budgets_capabilities.sql +72 -0
- package/dist/assets/modules/budgets/supabase/migrations/20260914122400_budgets_round_at_the_currency.sql +68 -0
- package/dist/assets/modules/budgets/supabase/migrations/20260914145048_budgets_accounts_in_use.sql +30 -0
- package/dist/assets/modules/budgets/supabase/migrations/20260914151812_budgets_grants_its_own_rights.sql +31 -0
- package/dist/assets/modules/budgets/supabase/migrations/20260918113954_budgets_client_reads.sql +20 -0
- package/dist/assets/modules/budgets/supabase/migrations/20260918150823_budgets_leave_with_the_company.sql +37 -0
- package/dist/assets/modules/schema/module.1.json +69 -0
- package/dist/assets/seed/00_currencies.sql +15 -0
- package/dist/assets/seed/00_territories.sql +280 -0
- package/dist/assets/seed/05_framework_generic.sql +110 -0
- package/dist/assets/seed/10_pack_be.sql +1284 -0
- package/dist/assets/seed/11_pack_fr.sql +1112 -0
- package/dist/assets/seed/12_pack_lu.sql +2484 -0
- package/dist/assets/seed/13_pack_ee.sql +733 -0
- package/dist/assets/seed/14_pack_gb.sql +796 -0
- package/dist/assets/seed/15_pack_us.sql +751 -0
- package/dist/assets/seed/90_demo_company.sql +368 -0
- package/dist/assets/seed/modules/assets/10_pack_be.sql +58 -0
- package/dist/assets/seed/modules/assets/11_pack_fr.sql +57 -0
- package/dist/assets/seed/modules/assets/14_pack_gb.sql +58 -0
- package/dist/assets/seed/modules/assets/15_pack_us.sql +60 -0
- package/dist/auth.d.ts +59 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +134 -0
- package/dist/auth.js.map +1 -0
- package/dist/bin.d.ts +6 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +8 -0
- package/dist/bin.js.map +1 -0
- package/dist/books.d.ts +60 -0
- package/dist/books.d.ts.map +1 -0
- package/dist/books.js +168 -0
- package/dist/books.js.map +1 -0
- package/dist/bootstrap.d.ts +236 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +459 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/bundle.d.ts +27 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +47 -0
- package/dist/bundle.js.map +1 -0
- package/dist/checklist.d.ts +35 -0
- package/dist/checklist.d.ts.map +1 -0
- package/dist/checklist.js +64 -0
- package/dist/checklist.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +318 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/company.d.ts +59 -0
- package/dist/commands/company.d.ts.map +1 -0
- package/dist/commands/company.js +287 -0
- package/dist/commands/company.js.map +1 -0
- package/dist/commands/contact.d.ts +9 -0
- package/dist/commands/contact.d.ts.map +1 -0
- package/dist/commands/contact.js +82 -0
- package/dist/commands/contact.js.map +1 -0
- package/dist/commands/demo.d.ts +19 -0
- package/dist/commands/demo.d.ts.map +1 -0
- package/dist/commands/demo.js +72 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/doctor.d.ts +12 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +68 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/document.d.ts +17 -0
- package/dist/commands/document.d.ts.map +1 -0
- package/dist/commands/document.js +217 -0
- package/dist/commands/document.js.map +1 -0
- package/dist/commands/init.d.ts +31 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +535 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +24 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +128 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/migrate.d.ts +30 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +115 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/module.d.ts +32 -0
- package/dist/commands/module.d.ts.map +1 -0
- package/dist/commands/module.js +285 -0
- package/dist/commands/module.js.map +1 -0
- package/dist/commands/pack.d.ts +22 -0
- package/dist/commands/pack.d.ts.map +1 -0
- package/dist/commands/pack.js +481 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/payment.d.ts +15 -0
- package/dist/commands/payment.d.ts.map +1 -0
- package/dist/commands/payment.js +97 -0
- package/dist/commands/payment.js.map +1 -0
- package/dist/commands/register.d.ts +20 -0
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/register.js +134 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/status.d.ts +8 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +134 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/whoami.d.ts +21 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +133 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/company.d.ts +16 -0
- package/dist/company.d.ts.map +1 -0
- package/dist/company.js +26 -0
- package/dist/company.js.map +1 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +50 -0
- package/dist/config.js.map +1 -0
- package/dist/connection.d.ts +79 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +116 -0
- package/dist/connection.js.map +1 -0
- package/dist/context.d.ts +47 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +93 -0
- package/dist/context.js.map +1 -0
- package/dist/doctor.d.ts +45 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +448 -0
- package/dist/doctor.js.map +1 -0
- package/dist/grants.d.ts +88 -0
- package/dist/grants.d.ts.map +1 -0
- package/dist/grants.js +174 -0
- package/dist/grants.js.map +1 -0
- package/dist/identity.d.ts +54 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +132 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory.d.ts +155 -0
- package/dist/inventory.d.ts.map +1 -0
- package/dist/inventory.js +303 -0
- package/dist/inventory.js.map +1 -0
- package/dist/migrations.d.ts +76 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +226 -0
- package/dist/migrations.js.map +1 -0
- package/dist/module/read.d.ts +91 -0
- package/dist/module/read.d.ts.map +1 -0
- package/dist/module/read.js +172 -0
- package/dist/module/read.js.map +1 -0
- package/dist/output.d.ts +110 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +173 -0
- package/dist/output.js.map +1 -0
- package/dist/pack/certification.d.ts +27 -0
- package/dist/pack/certification.d.ts.map +1 -0
- package/dist/pack/certification.js +38 -0
- package/dist/pack/certification.js.map +1 -0
- package/dist/pack/compile.d.ts +75 -0
- package/dist/pack/compile.d.ts.map +1 -0
- package/dist/pack/compile.js +801 -0
- package/dist/pack/compile.js.map +1 -0
- package/dist/pack/filing.d.ts +48 -0
- package/dist/pack/filing.d.ts.map +1 -0
- package/dist/pack/filing.js +56 -0
- package/dist/pack/filing.js.map +1 -0
- package/dist/pack/read.d.ts +766 -0
- package/dist/pack/read.d.ts.map +1 -0
- package/dist/pack/read.js +2336 -0
- package/dist/pack/read.js.map +1 -0
- package/dist/pack/schema.d.ts +26 -0
- package/dist/pack/schema.d.ts.map +1 -0
- package/dist/pack/schema.js +181 -0
- package/dist/pack/schema.js.map +1 -0
- package/dist/pack/territories.d.ts +98 -0
- package/dist/pack/territories.d.ts.map +1 -0
- package/dist/pack/territories.js +0 -0
- package/dist/pack/territories.js.map +1 -0
- package/dist/pack/upgrade.d.ts +86 -0
- package/dist/pack/upgrade.d.ts.map +1 -0
- package/dist/pack/upgrade.js +76 -0
- package/dist/pack/upgrade.js.map +1 -0
- package/dist/pack/vat-codes.d.ts +273 -0
- package/dist/pack/vat-codes.d.ts.map +1 -0
- package/dist/pack/vat-codes.js +513 -0
- package/dist/pack/vat-codes.js.map +1 -0
- package/dist/profiles.d.ts +67 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +187 -0
- package/dist/profiles.js.map +1 -0
- package/dist/prompt.d.ts +40 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +120 -0
- package/dist/prompt.js.map +1 -0
- package/dist/registry.d.ts +84 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +104 -0
- package/dist/registry.js.map +1 -0
- package/dist/rest.d.ts +81 -0
- package/dist/rest.d.ts.map +1 -0
- package/dist/rest.js +245 -0
- package/dist/rest.js.map +1 -0
- package/dist/schema.d.ts +15 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +15 -0
- package/dist/schema.js.map +1 -0
- package/dist/seeds.d.ts +27 -0
- package/dist/seeds.d.ts.map +1 -0
- package/dist/seeds.js +47 -0
- package/dist/seeds.js.map +1 -0
- package/dist/session.d.ts +39 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +92 -0
- package/dist/session.js.map +1 -0
- package/dist/sql.d.ts +48 -0
- package/dist/sql.d.ts.map +1 -0
- package/dist/sql.js +112 -0
- package/dist/sql.js.map +1 -0
- package/dist/status.d.ts +94 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +120 -0
- package/dist/status.js.map +1 -0
- package/dist/ui.d.ts +55 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +114 -0
- package/dist/ui.js.map +1 -0
- package/package.json +29 -0
- package/schema/output.1.json +613 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo company` — one company leaves an installation, and arrives in another.
|
|
3
|
+
*
|
|
4
|
+
* ekwo company export <company> --out <dir> write the archive of one company
|
|
5
|
+
* ekwo company import <dir> take an archive into this installation
|
|
6
|
+
*
|
|
7
|
+
* The archive is a directory: `manifest.json`, and one `data/<schema>.<table>.jsonl`
|
|
8
|
+
* per table, one row per line. `docs/company-archive.md` is the format, and it
|
|
9
|
+
* is written to be read without this CLI.
|
|
10
|
+
*
|
|
11
|
+
* **Exporting runs as a person, under row level security.** The connection the
|
|
12
|
+
* CLI holds belongs to the owner of the database, for whom every company is
|
|
13
|
+
* readable at once — which is exactly what `export_company_table()` refuses.
|
|
14
|
+
* So the export happens inside one transaction that steps down to
|
|
15
|
+
* `authenticated` and carries the claim of the member it acts for, the way
|
|
16
|
+
* PostgREST would have: the schema judges that person, and the snapshot is one
|
|
17
|
+
* snapshot, so the manifest and the rows cannot disagree.
|
|
18
|
+
*
|
|
19
|
+
* **The rows are never parsed here.** They are written as the database wrote
|
|
20
|
+
* them and read back the same way, because a JSON parser that meets `1.50`
|
|
21
|
+
* inside a jsonb column hands back `1.5`, and the checksum of a table is the
|
|
22
|
+
* checksum of its bytes.
|
|
23
|
+
*
|
|
24
|
+
* **Importing is one call.** The files are checked against the manifest first —
|
|
25
|
+
* a file damaged on the way is a finding of this CLI, not a refusal of the
|
|
26
|
+
* books — then handed whole to `import_company()`, which takes all of it or
|
|
27
|
+
* none of it.
|
|
28
|
+
*/
|
|
29
|
+
import { createHash } from 'node:crypto';
|
|
30
|
+
import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
|
|
31
|
+
import { join, resolve } from 'node:path';
|
|
32
|
+
import { rejectUnknownFlags, stringFlag, UsageError } from '../args.js';
|
|
33
|
+
import { CONNECTION_FLAGS, openDatabase } from '../context.js';
|
|
34
|
+
import { setResult } from '../output.js';
|
|
35
|
+
import { isInteractive } from '../prompt.js';
|
|
36
|
+
import { asUser, first } from '../sql.js';
|
|
37
|
+
import { bold, dim, heading, line, note, pairs, step, warn } from '../ui.js';
|
|
38
|
+
export const COMPANY_FLAGS = [...CONNECTION_FLAGS, 'out', 'as-user', 'owner', 'yes'];
|
|
39
|
+
/** `public.accounts`. What a table of an archive may be called, and nothing else. */
|
|
40
|
+
const TABLE_NAME = /^[a-z_][a-z0-9_]*\.[a-z_][a-z0-9_]*$/;
|
|
41
|
+
export async function companyCommand(args, deps = {}) {
|
|
42
|
+
rejectUnknownFlags(args, COMPANY_FLAGS);
|
|
43
|
+
const action = args.positional[0];
|
|
44
|
+
if (action === undefined)
|
|
45
|
+
throw new UsageError(`name a subcommand\n${usage()}`);
|
|
46
|
+
if (action === 'help') {
|
|
47
|
+
line(usage());
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
if (action !== 'export' && action !== 'import') {
|
|
51
|
+
throw new UsageError(`unknown subcommand: company ${action}\n${usage()}`);
|
|
52
|
+
}
|
|
53
|
+
const { db } = await openDatabase(args, { interactive: isInteractive(), connect: deps.connect });
|
|
54
|
+
try {
|
|
55
|
+
return action === 'export' ? await exportCommand(db, args) : await importCommand(db, args);
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
await db.close();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// -------------------------------------------------------------------- export
|
|
62
|
+
async function exportCommand(db, args) {
|
|
63
|
+
const given = args.positional[1];
|
|
64
|
+
const out = stringFlag(args, 'out');
|
|
65
|
+
if (out === undefined)
|
|
66
|
+
throw new UsageError(`--out <dir> is required: where the archive is written\n${usage()}`);
|
|
67
|
+
const company = await resolveCompany(db, given);
|
|
68
|
+
const actor = await resolveExporter(db, stringFlag(args, 'as-user'), company.id);
|
|
69
|
+
const dir = resolve(out);
|
|
70
|
+
const held = await readdir(dir).catch(() => []);
|
|
71
|
+
if (held.length > 0) {
|
|
72
|
+
throw new UsageError(`directory_not_empty: ${dir} holds ${held.length} entries. An archive is written into an empty directory.`);
|
|
73
|
+
}
|
|
74
|
+
await mkdir(join(dir, 'data'), { recursive: true });
|
|
75
|
+
heading(`Exporting ${company.name}`);
|
|
76
|
+
note(dim(`as ${actor}, under row level security`));
|
|
77
|
+
const written = await db.transaction(async (tx) => {
|
|
78
|
+
// One snapshot for the manifest and for every table.
|
|
79
|
+
await tx.exec('set transaction isolation level repeatable read');
|
|
80
|
+
await tx.query(`select set_config('request.jwt.claims', $1, true), set_config('ekwo.installing', '', true)`, [
|
|
81
|
+
JSON.stringify({ sub: actor, role: 'authenticated' }),
|
|
82
|
+
]);
|
|
83
|
+
await tx.exec('set local role authenticated');
|
|
84
|
+
// The act goes on the trail of the company before anything is read, so the
|
|
85
|
+
// trail the archive carries says it too.
|
|
86
|
+
await tx.query(`select note_company_export($1)`, [company.id]);
|
|
87
|
+
const row = await first(tx, `select export_company_manifest($1)::text as manifest`, [company.id]);
|
|
88
|
+
if (row === undefined)
|
|
89
|
+
throw new Error('export_company_manifest() answered nothing');
|
|
90
|
+
const manifest = JSON.parse(row.manifest);
|
|
91
|
+
let rowCount = 0;
|
|
92
|
+
for (const table of manifest.tables) {
|
|
93
|
+
if (!TABLE_NAME.test(table.name))
|
|
94
|
+
throw new Error(`archive_corrupt: ${table.name} is not the name of a table`);
|
|
95
|
+
const rows = await tx.query(`select r::text as row from export_company_table($1, $2) as r`, [company.id, table.name]);
|
|
96
|
+
const body = rows.map((r) => `${r.row}\n`).join('');
|
|
97
|
+
// The database counted and hashed the same rows in the same snapshot. A
|
|
98
|
+
// difference is a bug of this CLI or of the driver, and the archive is
|
|
99
|
+
// not one to keep.
|
|
100
|
+
if (rows.length !== table.rows || sha256(body) !== table.sha256) {
|
|
101
|
+
throw new Error(`archive_corrupt: ${table.name} was read as ${rows.length} rows that do not match the manifest`);
|
|
102
|
+
}
|
|
103
|
+
await writeFile(join(dir, 'data', `${table.name}.jsonl`), body, 'utf8');
|
|
104
|
+
rowCount += rows.length;
|
|
105
|
+
if (rows.length > 0)
|
|
106
|
+
step(`${table.name} ${dim(`${rows.length} rows`)}`);
|
|
107
|
+
}
|
|
108
|
+
await writeFile(join(dir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
|
|
109
|
+
return { manifest, total: rowCount };
|
|
110
|
+
});
|
|
111
|
+
const files = written.manifest.files?.list.length ?? 0;
|
|
112
|
+
line();
|
|
113
|
+
pairs([
|
|
114
|
+
['archive', dir],
|
|
115
|
+
['tables', String(written.manifest.tables.length)],
|
|
116
|
+
['rows', String(written.total)],
|
|
117
|
+
['files listed', `${files}, not carried`],
|
|
118
|
+
]);
|
|
119
|
+
if (files > 0) {
|
|
120
|
+
warn(`${files} attachment file(s) are listed in manifest.json and are not in the archive: carry them from the storage bucket, by their path.`);
|
|
121
|
+
}
|
|
122
|
+
setResult({
|
|
123
|
+
company: { id: company.id, name: company.name },
|
|
124
|
+
actingAs: actor,
|
|
125
|
+
out: dir,
|
|
126
|
+
tables: written.manifest.tables.length,
|
|
127
|
+
rows: written.total,
|
|
128
|
+
files: { listed: files, transported: false },
|
|
129
|
+
});
|
|
130
|
+
line();
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
133
|
+
// -------------------------------------------------------------------- import
|
|
134
|
+
/** Reads an archive directory, checks it against its manifest, and returns it as one JSON text. */
|
|
135
|
+
export async function readArchive(dir) {
|
|
136
|
+
let manifestText;
|
|
137
|
+
try {
|
|
138
|
+
manifestText = await readFile(join(dir, 'manifest.json'), 'utf8');
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
throw new UsageError(`not_an_archive: ${dir} holds no manifest.json`);
|
|
142
|
+
}
|
|
143
|
+
const manifest = JSON.parse(manifestText);
|
|
144
|
+
if (manifest.format !== 'ekwo.company-archive' || !Array.isArray(manifest.tables)) {
|
|
145
|
+
throw new UsageError(`not_an_archive: ${join(dir, 'manifest.json')} does not say it is an ekwo.company-archive`);
|
|
146
|
+
}
|
|
147
|
+
const parts = [];
|
|
148
|
+
let rowCount = 0;
|
|
149
|
+
for (const table of manifest.tables) {
|
|
150
|
+
// The name is what locates the file; `file` is there for a reader, and a
|
|
151
|
+
// path an archive chose is not one to open.
|
|
152
|
+
if (!TABLE_NAME.test(table.name))
|
|
153
|
+
throw new Error(`archive_corrupt: ${table.name} is not the name of a table`);
|
|
154
|
+
const body = await readFile(join(dir, 'data', `${table.name}.jsonl`), 'utf8').catch(() => undefined);
|
|
155
|
+
if (body === undefined)
|
|
156
|
+
throw new Error(`archive_corrupt: data/${table.name}.jsonl is listed in the manifest and missing`);
|
|
157
|
+
if (sha256(body) !== table.sha256) {
|
|
158
|
+
throw new Error(`archive_corrupt: data/${table.name}.jsonl does not have the checksum its manifest gives`);
|
|
159
|
+
}
|
|
160
|
+
const lines = body.split('\n').filter((l) => l.length > 0);
|
|
161
|
+
if (lines.length !== table.rows) {
|
|
162
|
+
throw new Error(`archive_corrupt: data/${table.name}.jsonl holds ${lines.length} rows and its manifest says ${table.rows}`);
|
|
163
|
+
}
|
|
164
|
+
rowCount += lines.length;
|
|
165
|
+
parts.push(`${JSON.stringify(table.name)}:[${lines.join(',')}]`);
|
|
166
|
+
}
|
|
167
|
+
return { manifest, text: `{"manifest":${manifestText},"tables":{${parts.join(',')}}}`, rows: rowCount };
|
|
168
|
+
}
|
|
169
|
+
async function importCommand(db, args) {
|
|
170
|
+
const given = args.positional[1];
|
|
171
|
+
if (given === undefined)
|
|
172
|
+
throw new UsageError(`name the directory of the archive\n${usage()}`);
|
|
173
|
+
const dir = resolve(given);
|
|
174
|
+
const actor = stringFlag(args, 'as-user');
|
|
175
|
+
const owner = stringFlag(args, 'owner') ?? actor;
|
|
176
|
+
const archive = await readArchive(dir);
|
|
177
|
+
heading(`Importing ${archive.manifest.company.name}`);
|
|
178
|
+
note(dim(`${archive.manifest.tables.length} tables, ${archive.rows} rows, checked against the manifest`));
|
|
179
|
+
const call = async () => {
|
|
180
|
+
const row = await first(db, `select import_company($1::jsonb, $2)::text as result`, [archive.text, owner ?? null]);
|
|
181
|
+
if (row === undefined)
|
|
182
|
+
throw new Error('import_company() answered nothing');
|
|
183
|
+
return JSON.parse(row.result);
|
|
184
|
+
};
|
|
185
|
+
// Without --as-user this connection is the installer, which is one of the
|
|
186
|
+
// two callers `import_company()` admits. With it, the schema judges that
|
|
187
|
+
// person: an administrator of the installation, or a refusal.
|
|
188
|
+
const result = actor === undefined ? await call() : await asUser(db, actor, call);
|
|
189
|
+
const files = count(result['files_to_carry']);
|
|
190
|
+
step(`${archive.manifest.company.name} is a company of this installation`);
|
|
191
|
+
line();
|
|
192
|
+
pairs([
|
|
193
|
+
['company', String(result['company_id'])],
|
|
194
|
+
['rows', String(result['rows'])],
|
|
195
|
+
['owner', owner ?? 'nobody yet'],
|
|
196
|
+
['files to carry', String(files)],
|
|
197
|
+
]);
|
|
198
|
+
if (owner === undefined) {
|
|
199
|
+
warn('No owner was named (--owner <uuid>): the company has no member yet. An administrator of the installation invites the first one.');
|
|
200
|
+
}
|
|
201
|
+
if (files > 0) {
|
|
202
|
+
warn(`${files} attachment file(s) are listed in manifest.json and did not travel: copy them into the storage bucket under the same paths.`);
|
|
203
|
+
}
|
|
204
|
+
setResult({
|
|
205
|
+
company: { id: String(result['company_id']), name: archive.manifest.company.name },
|
|
206
|
+
rows: count(result['rows']),
|
|
207
|
+
owner: owner ?? null,
|
|
208
|
+
tables: result['tables'],
|
|
209
|
+
files: { toCarry: files },
|
|
210
|
+
});
|
|
211
|
+
line();
|
|
212
|
+
return 0;
|
|
213
|
+
}
|
|
214
|
+
// ------------------------------------------------------------------- helpers
|
|
215
|
+
/**
|
|
216
|
+
* A count the database answered, as the JSON already carries it. Nothing is
|
|
217
|
+
* converted here: a count that did not arrive as a number is no count.
|
|
218
|
+
*/
|
|
219
|
+
function count(value) {
|
|
220
|
+
return typeof value === 'number' ? value : 0;
|
|
221
|
+
}
|
|
222
|
+
function sha256(text) {
|
|
223
|
+
return createHash('sha256').update(text, 'utf8').digest('hex');
|
|
224
|
+
}
|
|
225
|
+
async function resolveCompany(db, given) {
|
|
226
|
+
const companies = await db.query(`select id, name from companies order by name`);
|
|
227
|
+
if (given !== undefined) {
|
|
228
|
+
const match = companies.find((c) => c.id === given || c.name === given);
|
|
229
|
+
if (match === undefined) {
|
|
230
|
+
throw new UsageError(`unknown company: ${given}. This installation holds: ${companies.map((c) => c.name).join(', ') || 'none'}`);
|
|
231
|
+
}
|
|
232
|
+
return match;
|
|
233
|
+
}
|
|
234
|
+
const only = companies[0];
|
|
235
|
+
if (companies.length !== 1 || only === undefined) {
|
|
236
|
+
throw new UsageError(`name the company: this installation holds ${companies.length} — ` +
|
|
237
|
+
companies.map((c) => `${c.name} (${c.id})`).join(', '));
|
|
238
|
+
}
|
|
239
|
+
return only;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Who the export is signed by: whoever `--as-user` names, or a member who
|
|
243
|
+
* holds `company.export`, owners first. Nobody is invented — an archive says
|
|
244
|
+
* who took it, and the audit trail of the company says it too.
|
|
245
|
+
*
|
|
246
|
+
* Read from the tables: `member_capabilities()` answers about somebody else
|
|
247
|
+
* only to a member who manages the others, and this connection is nobody. It
|
|
248
|
+
* is a guess at whom to act for; the judgement is `has_capability()`'s, inside
|
|
249
|
+
* the export.
|
|
250
|
+
*/
|
|
251
|
+
async function resolveExporter(db, given, companyId) {
|
|
252
|
+
if (given !== undefined)
|
|
253
|
+
return given;
|
|
254
|
+
const member = await first(db, `select m.user_id
|
|
255
|
+
from company_members m
|
|
256
|
+
where m.company_id = $1
|
|
257
|
+
and not ('company.export' = any (m.capabilities_revoked))
|
|
258
|
+
and ('company.export' = any (m.capabilities_granted)
|
|
259
|
+
or exists (select 1 from role_capabilities rc
|
|
260
|
+
where rc.role = m.role and rc.capability = 'company.export'))
|
|
261
|
+
order by (m.role = 'owner') desc, m.created_at
|
|
262
|
+
limit 1`, [companyId]);
|
|
263
|
+
if (member === undefined) {
|
|
264
|
+
throw new Error(`no_exporter: no member of company ${companyId} holds company.export. Pass --as-user <uuid>.`);
|
|
265
|
+
}
|
|
266
|
+
return member.user_id;
|
|
267
|
+
}
|
|
268
|
+
function usage() {
|
|
269
|
+
return `${bold('ekwo company')} — one company leaves an installation, and arrives in another.
|
|
270
|
+
|
|
271
|
+
ekwo company export <company> --out <dir> Write the archive of one company: manifest.json
|
|
272
|
+
and one data/<table>.jsonl per table.
|
|
273
|
+
ekwo company import <dir> Take an archive into this installation, whole or
|
|
274
|
+
not at all. A company already here is refused.
|
|
275
|
+
|
|
276
|
+
--out <dir> Where the archive is written. Empty, or not there yet.
|
|
277
|
+
--as-user <uuid> export: the member the archive is read as, under row level security.
|
|
278
|
+
Defaults to an owner of the company. Needs company.export.
|
|
279
|
+
import: the administrator of the installation to act for. Defaults to
|
|
280
|
+
the installer, which this connection is.
|
|
281
|
+
--owner <uuid> import: who becomes the first owner. Members do not travel.
|
|
282
|
+
Defaults to --as-user.
|
|
283
|
+
|
|
284
|
+
The files the attachments point at are listed in manifest.json and are not carried.
|
|
285
|
+
`;
|
|
286
|
+
}
|
|
287
|
+
//# sourceMappingURL=company.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"company.js","sourceRoot":"","sources":["../../src/commands/company.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo contact add` and `ekwo contact list` — `createContact()` and
|
|
3
|
+
* `searchContacts()` of the core, which are the MCP server's `create_contact`
|
|
4
|
+
* and `search_contacts`.
|
|
5
|
+
*/
|
|
6
|
+
import { type ParsedArgs } from '../args.js';
|
|
7
|
+
import { type BooksDeps } from '../books.js';
|
|
8
|
+
export declare function contactCommand(args: ParsedArgs, deps?: BooksDeps): Promise<number>;
|
|
9
|
+
//# sourceMappingURL=contact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contact.d.ts","sourceRoot":"","sources":["../../src/commands/contact.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAA0D,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AACrG,OAAO,EAA8D,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAoBzG,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAK5F"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo contact add` and `ekwo contact list` — `createContact()` and
|
|
3
|
+
* `searchContacts()` of the core, which are the MCP server's `create_contact`
|
|
4
|
+
* and `search_contacts`.
|
|
5
|
+
*/
|
|
6
|
+
import { CONTACT_TYPES, createContact, searchContacts } from '@ekwo-ai/core';
|
|
7
|
+
import { UsageError, numberFlag, rejectUnknownFlags, stringFlag } from '../args.js';
|
|
8
|
+
import { BOOKS_FLAGS, CREATE_FLAGS, given, openBooks, stdinDocument } from '../books.js';
|
|
9
|
+
import { setResult } from '../output.js';
|
|
10
|
+
import { dim, heading, note, step, table } from '../ui.js';
|
|
11
|
+
const ADD_FLAGS = [...CREATE_FLAGS, 'type', 'vat', 'email', 'country', 'terms', 'aux', 'address', 'postal-code', 'city'];
|
|
12
|
+
const LIST_FLAGS = [...BOOKS_FLAGS, 'query', 'type', 'vat', 'limit'];
|
|
13
|
+
const ADD_FIELDS = [
|
|
14
|
+
'name', 'contact_type', 'vat_number', 'email', 'country', 'payment_terms_days', 'auxiliary_code',
|
|
15
|
+
'address_line1', 'postal_code', 'city', 'client_ref',
|
|
16
|
+
];
|
|
17
|
+
function contactType(value) {
|
|
18
|
+
if (value === undefined)
|
|
19
|
+
return undefined;
|
|
20
|
+
if (!CONTACT_TYPES.includes(value)) {
|
|
21
|
+
throw new UsageError(`bad_type: --type is one of ${CONTACT_TYPES.join(', ')}, got "${value}".`);
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
export async function contactCommand(args, deps = {}) {
|
|
26
|
+
const action = args.positional[0];
|
|
27
|
+
if (action === 'add')
|
|
28
|
+
return add(args, deps);
|
|
29
|
+
if (action === 'list')
|
|
30
|
+
return list(args, deps);
|
|
31
|
+
throw new UsageError('usage: ekwo contact add <name> [--type --vat --email --country --terms --ref] | ekwo contact list [--query --type --vat]');
|
|
32
|
+
}
|
|
33
|
+
async function add(args, deps) {
|
|
34
|
+
rejectUnknownFlags(args, ADD_FLAGS);
|
|
35
|
+
const input = await stdinDocument(args, deps, ADD_FIELDS);
|
|
36
|
+
const { backend, company } = await openBooks(args, deps);
|
|
37
|
+
const fields = given({
|
|
38
|
+
...input,
|
|
39
|
+
name: args.positional[1] ?? input['name'],
|
|
40
|
+
contact_type: contactType(stringFlag(args, 'type')) ?? input['contact_type'],
|
|
41
|
+
vat_number: stringFlag(args, 'vat') ?? input['vat_number'],
|
|
42
|
+
email: stringFlag(args, 'email') ?? input['email'],
|
|
43
|
+
country: stringFlag(args, 'country') ?? input['country'],
|
|
44
|
+
payment_terms_days: numberFlag(args, 'terms') ?? input['payment_terms_days'],
|
|
45
|
+
auxiliary_code: stringFlag(args, 'aux') ?? input['auxiliary_code'],
|
|
46
|
+
address_line1: stringFlag(args, 'address') ?? input['address_line1'],
|
|
47
|
+
postal_code: stringFlag(args, 'postal-code') ?? input['postal_code'],
|
|
48
|
+
city: stringFlag(args, 'city') ?? input['city'],
|
|
49
|
+
client_ref: stringFlag(args, 'ref') ?? input['client_ref'],
|
|
50
|
+
});
|
|
51
|
+
if (typeof fields.name !== 'string' || fields.name.length === 0) {
|
|
52
|
+
throw new UsageError('missing_argument: the name of the contact. `ekwo contact add "<name>"`, or `name` under --stdin.');
|
|
53
|
+
}
|
|
54
|
+
const result = (await createContact(backend, { ...fields, company_id: company.id }));
|
|
55
|
+
setResult(result);
|
|
56
|
+
heading('Contact');
|
|
57
|
+
const contact = result.contact;
|
|
58
|
+
if (result.replayed === true)
|
|
59
|
+
note(dim(`already created under the reference ${String(contact['client_ref'])}; nothing was written`));
|
|
60
|
+
step(`${String(contact['name'])} ${dim(String(contact['id']))}, in ${company.name}`);
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
async function list(args, deps) {
|
|
64
|
+
rejectUnknownFlags(args, LIST_FLAGS);
|
|
65
|
+
const { backend, company } = await openBooks(args, deps);
|
|
66
|
+
const result = (await searchContacts(backend, given({
|
|
67
|
+
company_id: company.id,
|
|
68
|
+
query: stringFlag(args, 'query'),
|
|
69
|
+
contact_type: contactType(stringFlag(args, 'type')),
|
|
70
|
+
vat_number: stringFlag(args, 'vat'),
|
|
71
|
+
limit: numberFlag(args, 'limit'),
|
|
72
|
+
})));
|
|
73
|
+
setResult(result);
|
|
74
|
+
heading(`Contacts of ${company.name}`);
|
|
75
|
+
if (result.contacts.length === 0)
|
|
76
|
+
note(dim('None.'));
|
|
77
|
+
else {
|
|
78
|
+
table([{ title: 'name' }, { title: 'type' }, { title: 'vat' }, { title: 'id' }], result.contacts.map((c) => [String(c['name']), String(c['contact_type']), String(c['vat_number'] ?? ''), dim(String(c['id']))]));
|
|
79
|
+
}
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=contact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contact.js","sourceRoot":"","sources":["../../src/commands/contact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo demo` — the sample company, on explicit request only.
|
|
3
|
+
*
|
|
4
|
+
* `90_demo_company.sql` invents a Belgian consultancy with a quarter of
|
|
5
|
+
* invoices, a matched payment and a bank statement. It is the fastest way to
|
|
6
|
+
* see what the schema does, and it has no place on real books: besides the
|
|
7
|
+
* company it also writes a fictional row into `auth.users` and makes that
|
|
8
|
+
* fictional user an instance administrator, because the seed has to stand
|
|
9
|
+
* alone on an empty database.
|
|
10
|
+
*
|
|
11
|
+
* So the command asks first, and it acts on behalf of a real administrator so
|
|
12
|
+
* the database's own rule — only an administrator appoints another — is
|
|
13
|
+
* satisfied rather than bypassed.
|
|
14
|
+
*/
|
|
15
|
+
import { type ParsedArgs } from '../args.js';
|
|
16
|
+
import { type CommandDeps } from '../context.js';
|
|
17
|
+
export declare const DEMO_FLAGS: readonly ["db-url", "db-password", "db-region", "project-ref", "supabase-url", "service-role-key", "admin-user-id", "yes"];
|
|
18
|
+
export declare function demoCommand(args: ParsedArgs, deps?: CommandDeps): Promise<number>;
|
|
19
|
+
//# sourceMappingURL=demo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.d.ts","sourceRoot":"","sources":["../../src/commands/demo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAA4C,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAEvF,OAAO,EAAkC,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAQjF,eAAO,MAAM,UAAU,4HAAyD,CAAC;AAEjF,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoD3F"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo demo` — the sample company, on explicit request only.
|
|
3
|
+
*
|
|
4
|
+
* `90_demo_company.sql` invents a Belgian consultancy with a quarter of
|
|
5
|
+
* invoices, a matched payment and a bank statement. It is the fastest way to
|
|
6
|
+
* see what the schema does, and it has no place on real books: besides the
|
|
7
|
+
* company it also writes a fictional row into `auth.users` and makes that
|
|
8
|
+
* fictional user an instance administrator, because the seed has to stand
|
|
9
|
+
* alone on an empty database.
|
|
10
|
+
*
|
|
11
|
+
* So the command asks first, and it acts on behalf of a real administrator so
|
|
12
|
+
* the database's own rule — only an administrator appoints another — is
|
|
13
|
+
* satisfied rather than bypassed.
|
|
14
|
+
*/
|
|
15
|
+
import { boolFlag, rejectUnknownFlags, stringFlag } from '../args.js';
|
|
16
|
+
import { seedDir } from '../bundle.js';
|
|
17
|
+
import { CONNECTION_FLAGS, openDatabase } from '../context.js';
|
|
18
|
+
import { confirm, isInteractive } from '../prompt.js';
|
|
19
|
+
import { anyAdminId } from '../registry.js';
|
|
20
|
+
import { applyDemoSeed } from '../seeds.js';
|
|
21
|
+
import { asUser, scalar } from '../sql.js';
|
|
22
|
+
import { setResult } from '../output.js';
|
|
23
|
+
import { dim, heading, line, note, skipped, step, warn } from '../ui.js';
|
|
24
|
+
export const DEMO_FLAGS = [...CONNECTION_FLAGS, 'admin-user-id', 'yes'];
|
|
25
|
+
export async function demoCommand(args, deps = {}) {
|
|
26
|
+
rejectUnknownFlags(args, DEMO_FLAGS);
|
|
27
|
+
const yes = boolFlag(args, 'yes');
|
|
28
|
+
const interactive = !yes && isInteractive();
|
|
29
|
+
const { db } = await openDatabase(args, { interactive, connect: deps.connect });
|
|
30
|
+
try {
|
|
31
|
+
heading('Demo company');
|
|
32
|
+
const already = await scalar(db, `select exists (select 1 from companies where vat_number = 'BE0123456749')`);
|
|
33
|
+
if (already === true) {
|
|
34
|
+
skipped('Exemple Conseil SRL is already here; the seed does nothing twice');
|
|
35
|
+
setResult({ applied: false, reason: 'already_there' });
|
|
36
|
+
line();
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
const companies = await scalar(db, 'select count(*)::text from companies');
|
|
40
|
+
if (companies !== '0') {
|
|
41
|
+
warn(`this installation already holds ${companies ?? '0'} compan(y/ies).`);
|
|
42
|
+
note(dim('The demo adds a fictional company and a fictional administrator alongside them.'));
|
|
43
|
+
if (!yes) {
|
|
44
|
+
const go = interactive ? await confirm('Add the demo data anyway?', false) : false;
|
|
45
|
+
if (!go) {
|
|
46
|
+
skipped('not applied');
|
|
47
|
+
setResult({ applied: false, reason: 'not_confirmed' });
|
|
48
|
+
note(dim('Pass --yes to apply it without being asked.'));
|
|
49
|
+
line();
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const adminUserId = stringFlag(args, 'admin-user-id') ?? (await anyAdminId(db));
|
|
55
|
+
if (adminUserId === undefined) {
|
|
56
|
+
// Nothing claimed yet: the seed can take the first seat itself.
|
|
57
|
+
await applyDemoSeed(db, seedDir());
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
await asUser(db, adminUserId, () => applyDemoSeed(db, seedDir()));
|
|
61
|
+
}
|
|
62
|
+
setResult({ applied: true });
|
|
63
|
+
step('Exemple Conseil SRL: 6 contacts, 10 documents, a matched payment, a bank statement');
|
|
64
|
+
note(dim('Everything in it is invented. Drop the company when you are done looking.'));
|
|
65
|
+
line();
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
await db.close();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demo.js","sourceRoot":"","sources":["../../src/commands/demo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo doctor` — the checks, printed.
|
|
3
|
+
*
|
|
4
|
+
* Exit code 1 when something is a problem, 0 otherwise. Warnings do not fail
|
|
5
|
+
* the command: an orphaned membership is worth knowing about and is not a
|
|
6
|
+
* reason for a CI job to go red.
|
|
7
|
+
*/
|
|
8
|
+
import { type ParsedArgs } from '../args.js';
|
|
9
|
+
import { type CommandDeps } from '../context.js';
|
|
10
|
+
export declare const DOCTOR_FLAGS: readonly ["db-url", "db-password", "db-region", "project-ref", "supabase-url", "service-role-key", "yes"];
|
|
11
|
+
export declare function doctorCommand(args: ParsedArgs, deps?: CommandDeps): Promise<number>;
|
|
12
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3E,OAAO,EAAkC,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AASjF,eAAO,MAAM,YAAY,2GAAwC,CAAC;AAsBlE,wBAAsB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmC7F"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo doctor` — the checks, printed.
|
|
3
|
+
*
|
|
4
|
+
* Exit code 1 when something is a problem, 0 otherwise. Warnings do not fail
|
|
5
|
+
* the command: an orphaned membership is worth knowing about and is not a
|
|
6
|
+
* reason for a CI job to go red.
|
|
7
|
+
*/
|
|
8
|
+
import { boolFlag, rejectUnknownFlags } from '../args.js';
|
|
9
|
+
import { migrationsDir } from '../bundle.js';
|
|
10
|
+
import { CONNECTION_FLAGS, openDatabase } from '../context.js';
|
|
11
|
+
import { doctor } from '../doctor.js';
|
|
12
|
+
import { listMigrations } from '../migrations.js';
|
|
13
|
+
import { allModuleMigrations, listModules } from '../module/read.js';
|
|
14
|
+
import { isInteractive } from '../prompt.js';
|
|
15
|
+
import { schemaIsInstalled } from '../bootstrap.js';
|
|
16
|
+
import { setResult } from '../output.js';
|
|
17
|
+
import { dim, green, heading, line, red, warn, yellow } from '../ui.js';
|
|
18
|
+
export const DOCTOR_FLAGS = [...CONNECTION_FLAGS, 'yes'];
|
|
19
|
+
/**
|
|
20
|
+
* The migrations this release carries, the socle's and the modules'.
|
|
21
|
+
*
|
|
22
|
+
* `ekwo migrate` installs the modules by default — a module is a schema whose
|
|
23
|
+
* tables are empty until a company enables it — and records their versions in
|
|
24
|
+
* the same history table as the socle's. So a gap computed against the socle
|
|
25
|
+
* alone reads eight module versions as history this CLI has no file for, and
|
|
26
|
+
* an installation that was merely kept up to date is reported as "ahead of
|
|
27
|
+
* this CLI: upgrade the CLI before migrating" — advice to upgrade something
|
|
28
|
+
* that is already current. Found by the end-to-end run of 14 September 2026
|
|
29
|
+
* against a real project, where `ekwo migrate` and `ekwo doctor` disagreed
|
|
30
|
+
* about the same database one command apart.
|
|
31
|
+
*/
|
|
32
|
+
async function everything() {
|
|
33
|
+
const modules = await listModules();
|
|
34
|
+
return [...(await listMigrations(migrationsDir())), ...allModuleMigrations(modules)].sort((a, b) => a.version.localeCompare(b.version));
|
|
35
|
+
}
|
|
36
|
+
export async function doctorCommand(args, deps = {}) {
|
|
37
|
+
rejectUnknownFlags(args, DOCTOR_FLAGS);
|
|
38
|
+
const interactive = !boolFlag(args, 'yes') && isInteractive();
|
|
39
|
+
const { db } = await openDatabase(args, { interactive, connect: deps.connect });
|
|
40
|
+
try {
|
|
41
|
+
if (!(await schemaIsInstalled(db))) {
|
|
42
|
+
heading('Doctor');
|
|
43
|
+
warn('the schema is not installed on this project. Run `ekwo init`.');
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
const migrations = await everything();
|
|
47
|
+
const report = await doctor(db, migrations);
|
|
48
|
+
setResult(report);
|
|
49
|
+
heading('Doctor');
|
|
50
|
+
for (const check of report.checks) {
|
|
51
|
+
const mark = check.severity === 'ok' ? green('ok') : check.severity === 'warning' ? yellow('warn') : red('fail');
|
|
52
|
+
line(` ${mark.padEnd(check.severity === 'ok' ? 6 : 8)} ${check.name}: ${check.summary}`);
|
|
53
|
+
for (const detail of check.details ?? [])
|
|
54
|
+
line(` ${dim(detail)}`);
|
|
55
|
+
}
|
|
56
|
+
line();
|
|
57
|
+
if (report.problems > 0) {
|
|
58
|
+
line(` ${red(`${report.problems} problem(s)`)}, ${report.warnings} warning(s).`);
|
|
59
|
+
return 1;
|
|
60
|
+
}
|
|
61
|
+
line(` ${green('No problems.')} ${report.warnings} warning(s).`);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
await db.close();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The verbs on a document: `invoice new`, `invoice line add`, `post`,
|
|
3
|
+
* `doc list` and `doc show`.
|
|
4
|
+
*
|
|
5
|
+
* Each is one function of the core — `createDocument()`, `addDocumentLine()`,
|
|
6
|
+
* `postDocument()`, `listDocuments()`, `getDocument()` — which the MCP server
|
|
7
|
+
* calls for `create_document`, `post_document`, `list_documents` and
|
|
8
|
+
* `get_document`. What is printed is what came back: the totals are the
|
|
9
|
+
* database's, the entry is the one `post_document()` wrote, and a refusal is
|
|
10
|
+
* left to `output.ts` to repeat word for word.
|
|
11
|
+
*/
|
|
12
|
+
import { type ParsedArgs } from '../args.js';
|
|
13
|
+
import { type BooksDeps } from '../books.js';
|
|
14
|
+
export declare function invoiceCommand(args: ParsedArgs, deps?: BooksDeps): Promise<number>;
|
|
15
|
+
export declare function postCommand(args: ParsedArgs, deps?: BooksDeps): Promise<number>;
|
|
16
|
+
export declare function docCommand(args: ParsedArgs, deps?: BooksDeps): Promise<number>;
|
|
17
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/commands/document.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiBH,OAAO,EAAiF,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC5H,OAAO,EAWL,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AA6ErB,wBAAsB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAK5F;AA0ED,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAczF;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,SAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAKxF"}
|