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
package/dist/company.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The company a name or an id refers to, among those a caller can see.
|
|
3
|
+
*
|
|
4
|
+
* A name is what a person types and a uuid is what a script passes, so both
|
|
5
|
+
* are accepted; an ambiguous name is refused rather than resolved to the first
|
|
6
|
+
* match, because working on the wrong company is not a mistake anybody
|
|
7
|
+
* notices the same day. The list is whatever the caller was allowed to read —
|
|
8
|
+
* every company for the installer's connection, the ones row level security
|
|
9
|
+
* lets through for a person — so a company somebody was never invited to is
|
|
10
|
+
* simply unknown, which is also all they should learn about it.
|
|
11
|
+
*/
|
|
12
|
+
import { UsageError } from './args.js';
|
|
13
|
+
export function matchCompany(companies, wanted) {
|
|
14
|
+
const asked = wanted.toLowerCase();
|
|
15
|
+
const matches = companies.filter((c) => c.id === asked || c.name.toLowerCase() === asked);
|
|
16
|
+
if (matches.length === 0) {
|
|
17
|
+
throw new UsageError(`unknown_company: no company called ${wanted}. This installation has: ${companies.length === 0 ? 'none' : companies.map((c) => c.name).join(', ')}`);
|
|
18
|
+
}
|
|
19
|
+
if (matches.length > 1) {
|
|
20
|
+
throw new UsageError(`ambiguous_company: ${matches.length} companies are called ${wanted}. Name one by its id: ${matches
|
|
21
|
+
.map((c) => c.id)
|
|
22
|
+
.join(', ')}`);
|
|
23
|
+
}
|
|
24
|
+
return matches[0];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=company.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"company.js","sourceRoot":"","sources":["../src/company.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,MAAM,UAAU,YAAY,CAAyC,SAAuB,EAAE,MAAc;IAC1G,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC;IAC1F,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,UAAU,CAClB,sCAAsC,MAAM,4BAC1C,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAC1E,EAAE,CACH,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,UAAU,CAClB,sBAAsB,OAAO,CAAC,MAAM,yBAAyB,MAAM,yBAAyB,OAAO;aAChG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChB,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAM,CAAC;AACzB,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo.json` — the one file the CLI writes, and what is deliberately not in it.
|
|
3
|
+
*
|
|
4
|
+
* It holds three things: which Supabase project this installation is on, which
|
|
5
|
+
* country's rules it was set up for, and which schema version it was at. That
|
|
6
|
+
* is enough for the next `ekwo status` or `ekwo migrate` to know where it is
|
|
7
|
+
* pointed without being told again.
|
|
8
|
+
*
|
|
9
|
+
* It holds no password, no service_role key and no connection string with
|
|
10
|
+
* credentials in it. Those are given per invocation, by flag, environment
|
|
11
|
+
* variable or prompt, and they are never written down here. A file that is
|
|
12
|
+
* safe to commit is a file that stays useful; a file with a key in it becomes
|
|
13
|
+
* a leak the first time somebody commits it.
|
|
14
|
+
*/
|
|
15
|
+
export declare const CONFIG_FILE = "ekwo.json";
|
|
16
|
+
export interface EkwoConfig {
|
|
17
|
+
project_url?: string;
|
|
18
|
+
country?: string;
|
|
19
|
+
schema_version?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function configPath(cwd?: string): string;
|
|
22
|
+
export declare function readConfig(cwd?: string): Promise<EkwoConfig | undefined>;
|
|
23
|
+
export declare function writeConfig(config: EkwoConfig, cwd?: string): Promise<string>;
|
|
24
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,eAAO,MAAM,WAAW,cAAc,CAAC;AAEvC,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD,wBAAgB,UAAU,CAAC,GAAG,SAAgB,GAAG,MAAM,CAEtD;AAED,wBAAsB,UAAU,CAAC,GAAG,SAAgB,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAcrF;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,SAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAU1F"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo.json` — the one file the CLI writes, and what is deliberately not in it.
|
|
3
|
+
*
|
|
4
|
+
* It holds three things: which Supabase project this installation is on, which
|
|
5
|
+
* country's rules it was set up for, and which schema version it was at. That
|
|
6
|
+
* is enough for the next `ekwo status` or `ekwo migrate` to know where it is
|
|
7
|
+
* pointed without being told again.
|
|
8
|
+
*
|
|
9
|
+
* It holds no password, no service_role key and no connection string with
|
|
10
|
+
* credentials in it. Those are given per invocation, by flag, environment
|
|
11
|
+
* variable or prompt, and they are never written down here. A file that is
|
|
12
|
+
* safe to commit is a file that stays useful; a file with a key in it becomes
|
|
13
|
+
* a leak the first time somebody commits it.
|
|
14
|
+
*/
|
|
15
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
export const CONFIG_FILE = 'ekwo.json';
|
|
18
|
+
const HEADER = 'No secrets live here. The database password and the service_role key are ' +
|
|
19
|
+
'given per command, through --flags, the environment or a prompt.';
|
|
20
|
+
export function configPath(cwd = process.cwd()) {
|
|
21
|
+
return join(cwd, CONFIG_FILE);
|
|
22
|
+
}
|
|
23
|
+
export async function readConfig(cwd = process.cwd()) {
|
|
24
|
+
try {
|
|
25
|
+
const text = await readFile(configPath(cwd), 'utf8');
|
|
26
|
+
const parsed = JSON.parse(text);
|
|
27
|
+
return {
|
|
28
|
+
...(typeof parsed['project_url'] === 'string' ? { project_url: parsed['project_url'] } : {}),
|
|
29
|
+
...(typeof parsed['country'] === 'string' ? { country: parsed['country'] } : {}),
|
|
30
|
+
...(typeof parsed['schema_version'] === 'string'
|
|
31
|
+
? { schema_version: parsed['schema_version'] }
|
|
32
|
+
: {}),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export async function writeConfig(config, cwd = process.cwd()) {
|
|
40
|
+
const path = configPath(cwd);
|
|
41
|
+
const body = {
|
|
42
|
+
$comment: HEADER,
|
|
43
|
+
...(config.project_url !== undefined ? { project_url: config.project_url } : {}),
|
|
44
|
+
...(config.country !== undefined ? { country: config.country } : {}),
|
|
45
|
+
...(config.schema_version !== undefined ? { schema_version: config.schema_version } : {}),
|
|
46
|
+
};
|
|
47
|
+
await writeFile(path, `${JSON.stringify(body, null, 2)}\n`, 'utf8');
|
|
48
|
+
return path;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;AAQvC,MAAM,MAAM,GACV,2EAA2E;IAC3E,kEAAkE,CAAC;AAErE,MAAM,UAAU,UAAU,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAC5C,OAAO,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAClD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAC;QAC3D,OAAO;YACL,GAAG,CAAC,OAAO,MAAM,CAAC,aAAa,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5F,GAAG,CAAC,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChF,GAAG,CAAC,OAAO,MAAM,CAAC,gBAAgB,CAAC,KAAK,QAAQ;gBAC9C,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,gBAAgB,CAAC,EAAE;gBAC9C,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAkB,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACvE,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG;QACX,QAAQ,EAAE,MAAM;QAChB,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,GAAG,CAAC,MAAM,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1F,CAAC;IACF,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpE,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the connection details come from, and where they do not go.
|
|
3
|
+
*
|
|
4
|
+
* Three sources, in this order: a flag, an environment variable, a prompt.
|
|
5
|
+
* Nothing else. In particular the CLI never reads a secret out of a file it
|
|
6
|
+
* wrote and never writes one into a file — not into `ekwo.json`, not into a
|
|
7
|
+
* dotfile in the home directory, not into a cache. A service_role key can do
|
|
8
|
+
* anything to the project it belongs to; leaving a copy of it on disk because
|
|
9
|
+
* it saved a paste is not a trade worth making. `.env.example` documents the
|
|
10
|
+
* variables so an operator can put them somewhere *they* chose.
|
|
11
|
+
*
|
|
12
|
+
* The reliable way to give the CLI a database is `--db-url`, copied from the
|
|
13
|
+
* Supabase dashboard under Connect → Session pooler. `--project-ref` with
|
|
14
|
+
* `--db-password` and `--db-region` is the convenience, and it no longer
|
|
15
|
+
* guesses: the pooler hostname carries a generation prefix as well as a
|
|
16
|
+
* region, so both `aws-0-<region>` and `aws-1-<region>` are tried and the one
|
|
17
|
+
* that answers is kept and printed. There is deliberately no helper that
|
|
18
|
+
* builds the direct host `db.<ref>.supabase.co`: it resolves to an IPv6
|
|
19
|
+
* address only on projects created since 2024, so deriving it on the
|
|
20
|
+
* operator's behalf produces a hang rather than an error. Someone who wants it
|
|
21
|
+
* passes it as `--db-url`.
|
|
22
|
+
*/
|
|
23
|
+
export interface Connection {
|
|
24
|
+
/** Postgres connection string. Always present once resolved. */
|
|
25
|
+
dbUrl: string;
|
|
26
|
+
/** `https://<ref>.supabase.co`, when known. Needed to create the first user. */
|
|
27
|
+
supabaseUrl?: string | undefined;
|
|
28
|
+
/** Needed to create the first user, and never stored. */
|
|
29
|
+
serviceRoleKey?: string | undefined;
|
|
30
|
+
projectRef?: string | undefined;
|
|
31
|
+
}
|
|
32
|
+
export declare const ENV_DB_URL = "EKWO_DB_URL";
|
|
33
|
+
export declare const ENV_DB_URL_FALLBACK = "SUPABASE_DB_URL";
|
|
34
|
+
export declare const ENV_SUPABASE_URL = "SUPABASE_URL";
|
|
35
|
+
export declare const ENV_SERVICE_ROLE_KEY = "SUPABASE_SERVICE_ROLE_KEY";
|
|
36
|
+
/** The project ref out of whatever we were given, or `undefined`. */
|
|
37
|
+
export declare function projectRefFrom(value: string | undefined): string | undefined;
|
|
38
|
+
export declare function supabaseUrlFor(projectRef: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* The two pooler generations Supabase issues today. Both are tried, so the
|
|
41
|
+
* order is only which one costs a round trip when it is the wrong one.
|
|
42
|
+
*/
|
|
43
|
+
export declare const POOLER_GENERATIONS: readonly ["aws-0", "aws-1"];
|
|
44
|
+
/**
|
|
45
|
+
* The session pooler, on port 5432, for one generation prefix.
|
|
46
|
+
*
|
|
47
|
+
* Session mode — not the transaction pooler on 6543 — because a migration
|
|
48
|
+
* needs a session: advisory locks, `set local`, and a multi-statement file
|
|
49
|
+
* applied as one command.
|
|
50
|
+
*/
|
|
51
|
+
export declare function poolerUrl(projectRef: string, password: string, region: string, generation: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Every pooler host worth trying for a ref and a region.
|
|
54
|
+
*
|
|
55
|
+
* The generation prefix is not derivable. A project created in `eu-west-3` in
|
|
56
|
+
* September 2026 answered on `aws-1-eu-west-3` and returned "Tenant or user
|
|
57
|
+
* not found" on `aws-0-eu-west-3`; older projects are the other way round.
|
|
58
|
+
* Building one of them and calling it the answer is the bug this replaces.
|
|
59
|
+
*/
|
|
60
|
+
export declare function poolerCandidates(projectRef: string, password: string, region: string): string[];
|
|
61
|
+
/** The host of a connection string, for a message that names what answered. */
|
|
62
|
+
export declare function hostOf(dbUrl: string): string;
|
|
63
|
+
/** Answers whether a connection string reaches a database. */
|
|
64
|
+
export type Probe = (dbUrl: string) => Promise<boolean>;
|
|
65
|
+
export declare class NoPoolerHostError extends Error {
|
|
66
|
+
readonly tried: string[];
|
|
67
|
+
constructor(tried: string[]);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Picks the pooler host that answers, trying each generation in turn.
|
|
71
|
+
*
|
|
72
|
+
* Returns the string that worked, so the caller can print the host and the
|
|
73
|
+
* operator learns which one their project is on.
|
|
74
|
+
*/
|
|
75
|
+
export declare function pickPoolerUrl(projectRef: string, password: string, region: string, probe: Probe): Promise<string>;
|
|
76
|
+
export declare function looksLikeConnectionString(value: string): boolean;
|
|
77
|
+
/** A connection string with `sslmode=require` added when it says nothing. */
|
|
78
|
+
export declare function withSsl(dbUrl: string): string;
|
|
79
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,yDAAyD;IACzD,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,eAAO,MAAM,UAAU,gBAAgB,CAAC;AACxC,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AACrD,eAAO,MAAM,gBAAgB,iBAAiB,CAAC;AAC/C,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AAEhE,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAmB5E;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,6BAA8B,CAAC;AAE9D;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,MAAM,EAAE,CAIV;AAED,+EAA+E;AAC/E,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,8DAA8D;AAC9D,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAExD,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE;gBAAf,KAAK,EAAE,MAAM,EAAE;CAOrC;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,GACX,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI7C"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the connection details come from, and where they do not go.
|
|
3
|
+
*
|
|
4
|
+
* Three sources, in this order: a flag, an environment variable, a prompt.
|
|
5
|
+
* Nothing else. In particular the CLI never reads a secret out of a file it
|
|
6
|
+
* wrote and never writes one into a file — not into `ekwo.json`, not into a
|
|
7
|
+
* dotfile in the home directory, not into a cache. A service_role key can do
|
|
8
|
+
* anything to the project it belongs to; leaving a copy of it on disk because
|
|
9
|
+
* it saved a paste is not a trade worth making. `.env.example` documents the
|
|
10
|
+
* variables so an operator can put them somewhere *they* chose.
|
|
11
|
+
*
|
|
12
|
+
* The reliable way to give the CLI a database is `--db-url`, copied from the
|
|
13
|
+
* Supabase dashboard under Connect → Session pooler. `--project-ref` with
|
|
14
|
+
* `--db-password` and `--db-region` is the convenience, and it no longer
|
|
15
|
+
* guesses: the pooler hostname carries a generation prefix as well as a
|
|
16
|
+
* region, so both `aws-0-<region>` and `aws-1-<region>` are tried and the one
|
|
17
|
+
* that answers is kept and printed. There is deliberately no helper that
|
|
18
|
+
* builds the direct host `db.<ref>.supabase.co`: it resolves to an IPv6
|
|
19
|
+
* address only on projects created since 2024, so deriving it on the
|
|
20
|
+
* operator's behalf produces a hang rather than an error. Someone who wants it
|
|
21
|
+
* passes it as `--db-url`.
|
|
22
|
+
*/
|
|
23
|
+
export const ENV_DB_URL = 'EKWO_DB_URL';
|
|
24
|
+
export const ENV_DB_URL_FALLBACK = 'SUPABASE_DB_URL';
|
|
25
|
+
export const ENV_SUPABASE_URL = 'SUPABASE_URL';
|
|
26
|
+
export const ENV_SERVICE_ROLE_KEY = 'SUPABASE_SERVICE_ROLE_KEY';
|
|
27
|
+
/** The project ref out of whatever we were given, or `undefined`. */
|
|
28
|
+
export function projectRefFrom(value) {
|
|
29
|
+
if (value === undefined || value.length === 0)
|
|
30
|
+
return undefined;
|
|
31
|
+
// https://abcdefghijklmnopqrst.supabase.co
|
|
32
|
+
const host = /^https?:\/\/([a-z0-9-]+)\.supabase\.(co|in|red)/i.exec(value);
|
|
33
|
+
if (host !== null)
|
|
34
|
+
return host[1];
|
|
35
|
+
// postgresql://postgres.<ref>:password@aws-0-eu-central-1.pooler.supabase.com:5432/postgres
|
|
36
|
+
const pooler = /\/\/postgres\.([a-z0-9]+):/i.exec(value);
|
|
37
|
+
if (pooler !== null)
|
|
38
|
+
return pooler[1];
|
|
39
|
+
// postgresql://postgres:password@db.<ref>.supabase.co:5432/postgres
|
|
40
|
+
const direct = /@db\.([a-z0-9]+)\.supabase\./i.exec(value);
|
|
41
|
+
if (direct !== null)
|
|
42
|
+
return direct[1];
|
|
43
|
+
// A bare ref: twenty lowercase letters is what Supabase issues.
|
|
44
|
+
if (/^[a-z]{20}$/.test(value))
|
|
45
|
+
return value;
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
export function supabaseUrlFor(projectRef) {
|
|
49
|
+
return `https://${projectRef}.supabase.co`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The two pooler generations Supabase issues today. Both are tried, so the
|
|
53
|
+
* order is only which one costs a round trip when it is the wrong one.
|
|
54
|
+
*/
|
|
55
|
+
export const POOLER_GENERATIONS = ['aws-0', 'aws-1'];
|
|
56
|
+
/**
|
|
57
|
+
* The session pooler, on port 5432, for one generation prefix.
|
|
58
|
+
*
|
|
59
|
+
* Session mode — not the transaction pooler on 6543 — because a migration
|
|
60
|
+
* needs a session: advisory locks, `set local`, and a multi-statement file
|
|
61
|
+
* applied as one command.
|
|
62
|
+
*/
|
|
63
|
+
export function poolerUrl(projectRef, password, region, generation) {
|
|
64
|
+
return `postgresql://postgres.${projectRef}:${encodeURIComponent(password)}@${generation}-${region}.pooler.supabase.com:5432/postgres`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Every pooler host worth trying for a ref and a region.
|
|
68
|
+
*
|
|
69
|
+
* The generation prefix is not derivable. A project created in `eu-west-3` in
|
|
70
|
+
* September 2026 answered on `aws-1-eu-west-3` and returned "Tenant or user
|
|
71
|
+
* not found" on `aws-0-eu-west-3`; older projects are the other way round.
|
|
72
|
+
* Building one of them and calling it the answer is the bug this replaces.
|
|
73
|
+
*/
|
|
74
|
+
export function poolerCandidates(projectRef, password, region) {
|
|
75
|
+
return POOLER_GENERATIONS.map((generation) => poolerUrl(projectRef, password, region, generation));
|
|
76
|
+
}
|
|
77
|
+
/** The host of a connection string, for a message that names what answered. */
|
|
78
|
+
export function hostOf(dbUrl) {
|
|
79
|
+
const match = /@([^/:?]+)/.exec(dbUrl);
|
|
80
|
+
return match?.[1] ?? dbUrl;
|
|
81
|
+
}
|
|
82
|
+
export class NoPoolerHostError extends Error {
|
|
83
|
+
tried;
|
|
84
|
+
constructor(tried) {
|
|
85
|
+
super(`no_pooler_host: none of ${tried.join(', ')} answered. ` +
|
|
86
|
+
'Copy the connection string from your Supabase dashboard — Connect → Session pooler — ' +
|
|
87
|
+
'and pass it as --db-url. That string is the only form that is not derived.');
|
|
88
|
+
this.tried = tried;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Picks the pooler host that answers, trying each generation in turn.
|
|
93
|
+
*
|
|
94
|
+
* Returns the string that worked, so the caller can print the host and the
|
|
95
|
+
* operator learns which one their project is on.
|
|
96
|
+
*/
|
|
97
|
+
export async function pickPoolerUrl(projectRef, password, region, probe) {
|
|
98
|
+
const candidates = poolerCandidates(projectRef, password, region);
|
|
99
|
+
for (const candidate of candidates) {
|
|
100
|
+
if (await probe(withSsl(candidate)))
|
|
101
|
+
return candidate;
|
|
102
|
+
}
|
|
103
|
+
throw new NoPoolerHostError(candidates.map(hostOf));
|
|
104
|
+
}
|
|
105
|
+
export function looksLikeConnectionString(value) {
|
|
106
|
+
return /^postgres(ql)?:\/\//i.test(value);
|
|
107
|
+
}
|
|
108
|
+
/** A connection string with `sslmode=require` added when it says nothing. */
|
|
109
|
+
export function withSsl(dbUrl) {
|
|
110
|
+
if (/[?&]sslmode=/i.test(dbUrl))
|
|
111
|
+
return dbUrl;
|
|
112
|
+
if (/localhost|127\.0\.0\.1/.test(dbUrl))
|
|
113
|
+
return dbUrl;
|
|
114
|
+
return `${dbUrl}${dbUrl.includes('?') ? '&' : '?'}sslmode=require`;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.js","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAYH,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC;AACxC,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AACrD,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAC/C,MAAM,CAAC,MAAM,oBAAoB,GAAG,2BAA2B,CAAC;AAEhE,qEAAqE;AACrE,MAAM,UAAU,cAAc,CAAC,KAAyB;IACtD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAEhE,2CAA2C;IAC3C,MAAM,IAAI,GAAG,kDAAkD,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5E,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;IAElC,4FAA4F;IAC5F,MAAM,MAAM,GAAG,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzD,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IAEtC,oEAAoE;IACpE,MAAM,MAAM,GAAG,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;IAEtC,gEAAgE;IAChE,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAE5C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,OAAO,WAAW,UAAU,cAAc,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,OAAO,CAAU,CAAC;AAE9D;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,UAAkB,EAClB,QAAgB,EAChB,MAAc,EACd,UAAkB;IAElB,OAAO,yBAAyB,UAAU,IAAI,kBAAkB,CAAC,QAAQ,CAAC,IAAI,UAAU,IAAI,MAAM,oCAAoC,CAAC;AACzI,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAAkB,EAClB,QAAgB,EAChB,MAAc;IAEd,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAC3C,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CACpD,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,MAAM,CAAC,KAAa;IAClC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;AAC7B,CAAC;AAKD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACrB;IAArB,YAAqB,KAAe;QAClC,KAAK,CACH,2BAA2B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa;YACtD,uFAAuF;YACvF,4EAA4E,CAC/E,CAAC;QALiB,UAAK,GAAL,KAAK,CAAU;IAMpC,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAAkB,EAClB,QAAgB,EAChB,MAAc,EACd,KAAY;IAEZ,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAClE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,MAAM,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;IACxD,CAAC;IACD,MAAM,IAAI,iBAAiB,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAa;IACrD,OAAO,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5C,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9C,IAAI,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvD,OAAO,GAAG,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning flags, environment variables and questions into a connection.
|
|
3
|
+
*
|
|
4
|
+
* Every command starts here, so the rules about where a secret may come from
|
|
5
|
+
* are written once. See `connection.ts` for why none of them is a file.
|
|
6
|
+
*/
|
|
7
|
+
import type { ParsedArgs } from './args.js';
|
|
8
|
+
import { type Connection, type Probe } from './connection.js';
|
|
9
|
+
import { type SqlClient } from './sql.js';
|
|
10
|
+
export declare const CONNECTION_FLAGS: readonly ["db-url", "db-password", "db-region", "project-ref", "supabase-url", "service-role-key"];
|
|
11
|
+
export interface ResolveOptions {
|
|
12
|
+
/** Ask for what is missing. False in `--yes` runs and when stdin is not a terminal. */
|
|
13
|
+
interactive: boolean;
|
|
14
|
+
env?: NodeJS.ProcessEnv;
|
|
15
|
+
/**
|
|
16
|
+
* How a candidate pooler host is tried. Injected so the resolution can be
|
|
17
|
+
* tested without a network, and so nothing else in this file knows a driver
|
|
18
|
+
* exists.
|
|
19
|
+
*/
|
|
20
|
+
probe?: Probe;
|
|
21
|
+
/** How the database is opened. See `CommandDeps`. */
|
|
22
|
+
connect?: Connector | undefined;
|
|
23
|
+
}
|
|
24
|
+
/** Opens a connection string. The network driver, unless a test says otherwise. */
|
|
25
|
+
export type Connector = (dbUrl: string) => Promise<SqlClient>;
|
|
26
|
+
/**
|
|
27
|
+
* What a command may be handed instead of reaching for it.
|
|
28
|
+
*
|
|
29
|
+
* One thing: the way a database is opened. The tests plug PGlite in here and
|
|
30
|
+
* then run the commands themselves — flags, output, exit code — rather than
|
|
31
|
+
* the functions underneath them, which is the only way to hold every command
|
|
32
|
+
* to the same output contract.
|
|
33
|
+
*/
|
|
34
|
+
export interface CommandDeps {
|
|
35
|
+
connect?: Connector | undefined;
|
|
36
|
+
}
|
|
37
|
+
/** Opens the connection, closes it, and answers whether that worked. */
|
|
38
|
+
export declare const connectProbe: Probe;
|
|
39
|
+
/** Works out how to reach the database, without connecting yet. */
|
|
40
|
+
export declare function resolveConnection(args: ParsedArgs, options: ResolveOptions): Promise<Connection>;
|
|
41
|
+
export interface Context {
|
|
42
|
+
db: SqlClient;
|
|
43
|
+
connection: Connection;
|
|
44
|
+
}
|
|
45
|
+
/** Resolves and opens. The caller closes. */
|
|
46
|
+
export declare function openDatabase(args: ParsedArgs, options: ResolveOptions): Promise<Context>;
|
|
47
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,EAWL,KAAK,UAAU,EACf,KAAK,KAAK,EACX,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAGnD,eAAO,MAAM,gBAAgB,oGAOnB,CAAC;AAEX,MAAM,WAAW,cAAc;IAC7B,uFAAuF;IACvF,WAAW,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,qDAAqD;IACrD,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACjC;AAED,mFAAmF;AACnF,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAE9D;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACjC;AAED,wEAAwE;AACxE,eAAO,MAAM,YAAY,EAAE,KAQ1B,CAAC;AAEF,mEAAmE;AACnE,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC,CAmErB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,SAAS,CAAC;IACd,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,6CAA6C;AAC7C,wBAAsB,YAAY,CAChC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,CASlB"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning flags, environment variables and questions into a connection.
|
|
3
|
+
*
|
|
4
|
+
* Every command starts here, so the rules about where a secret may come from
|
|
5
|
+
* are written once. See `connection.ts` for why none of them is a file.
|
|
6
|
+
*/
|
|
7
|
+
import { UsageError, stringFlag } from './args.js';
|
|
8
|
+
import { ENV_DB_URL, ENV_DB_URL_FALLBACK, ENV_SERVICE_ROLE_KEY, ENV_SUPABASE_URL, hostOf, looksLikeConnectionString, pickPoolerUrl, projectRefFrom, supabaseUrlFor, withSsl, } from './connection.js';
|
|
9
|
+
import { NotInteractiveError, askSecret, isInteractive } from './prompt.js';
|
|
10
|
+
import { connect } from './sql.js';
|
|
11
|
+
import { dim, note } from './ui.js';
|
|
12
|
+
export const CONNECTION_FLAGS = [
|
|
13
|
+
'db-url',
|
|
14
|
+
'db-password',
|
|
15
|
+
'db-region',
|
|
16
|
+
'project-ref',
|
|
17
|
+
'supabase-url',
|
|
18
|
+
'service-role-key',
|
|
19
|
+
];
|
|
20
|
+
/** Opens the connection, closes it, and answers whether that worked. */
|
|
21
|
+
export const connectProbe = async (dbUrl) => {
|
|
22
|
+
try {
|
|
23
|
+
const db = await connect(dbUrl);
|
|
24
|
+
await db.close();
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/** Works out how to reach the database, without connecting yet. */
|
|
32
|
+
export async function resolveConnection(args, options) {
|
|
33
|
+
const env = options.env ?? process.env;
|
|
34
|
+
const interactive = options.interactive && isInteractive();
|
|
35
|
+
const supabaseUrlGiven = stringFlag(args, 'supabase-url') ?? env[ENV_SUPABASE_URL];
|
|
36
|
+
const serviceRoleKey = stringFlag(args, 'service-role-key') ?? env[ENV_SERVICE_ROLE_KEY];
|
|
37
|
+
let dbUrl = stringFlag(args, 'db-url') ?? env[ENV_DB_URL] ?? env[ENV_DB_URL_FALLBACK];
|
|
38
|
+
let projectRef = projectRefFrom(stringFlag(args, 'project-ref')) ??
|
|
39
|
+
projectRefFrom(supabaseUrlGiven) ??
|
|
40
|
+
projectRefFrom(dbUrl);
|
|
41
|
+
const region = stringFlag(args, 'db-region');
|
|
42
|
+
if (dbUrl === undefined && projectRef !== undefined && region !== undefined) {
|
|
43
|
+
const password = stringFlag(args, 'db-password') ??
|
|
44
|
+
env['EKWO_DB_PASSWORD'] ??
|
|
45
|
+
(interactive
|
|
46
|
+
? await askSecret(`Database password for project ${projectRef}:`)
|
|
47
|
+
: undefined);
|
|
48
|
+
if (password === undefined || password.length === 0) {
|
|
49
|
+
throw new NotInteractiveError('the database password', '--db-password or --db-url');
|
|
50
|
+
}
|
|
51
|
+
// Both pooler generations are tried and the one that answers is kept. The
|
|
52
|
+
// prefix is not derivable from the region, and building one of the two and
|
|
53
|
+
// calling it the host is how `--db-region` used to fail: the connection
|
|
54
|
+
// was refused with "Tenant or user not found", which reads like a wrong
|
|
55
|
+
// password rather than a wrong hostname.
|
|
56
|
+
dbUrl = await pickPoolerUrl(projectRef, password, region, options.probe ?? connectProbe);
|
|
57
|
+
note(dim(`Session pooler: ${hostOf(dbUrl)}`));
|
|
58
|
+
}
|
|
59
|
+
// No `--db-region`, or no ref at all: ask for the string the dashboard
|
|
60
|
+
// prints. The direct host `db.<ref>.supabase.co` is not built here on the
|
|
61
|
+
// operator's behalf — it resolves to IPv6 only on any recent project, so
|
|
62
|
+
// deriving it silently produces a hang rather than an answer.
|
|
63
|
+
if (dbUrl === undefined) {
|
|
64
|
+
if (!interactive) {
|
|
65
|
+
throw new NotInteractiveError('the database connection string', '--db-url (or --project-ref with --db-password and --db-region)');
|
|
66
|
+
}
|
|
67
|
+
const answer = await askSecret('Postgres connection string (Supabase dashboard → Connect → Session pooler):');
|
|
68
|
+
if (!looksLikeConnectionString(answer)) {
|
|
69
|
+
throw new UsageError(`bad_connection_string: expected something starting with postgresql://, got "${answer.slice(0, 24)}…"`);
|
|
70
|
+
}
|
|
71
|
+
dbUrl = answer;
|
|
72
|
+
projectRef = projectRef ?? projectRefFrom(dbUrl);
|
|
73
|
+
}
|
|
74
|
+
const supabaseUrl = supabaseUrlGiven ?? (projectRef !== undefined ? supabaseUrlFor(projectRef) : undefined);
|
|
75
|
+
return {
|
|
76
|
+
dbUrl: withSsl(dbUrl),
|
|
77
|
+
...(supabaseUrl !== undefined ? { supabaseUrl } : {}),
|
|
78
|
+
...(serviceRoleKey !== undefined ? { serviceRoleKey } : {}),
|
|
79
|
+
...(projectRef !== undefined ? { projectRef } : {}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Resolves and opens. The caller closes. */
|
|
83
|
+
export async function openDatabase(args, options) {
|
|
84
|
+
const connection = await resolveConnection(args, options);
|
|
85
|
+
const db = await (options.connect ?? connect)(connection.dbUrl);
|
|
86
|
+
// The exception, announced. Everything that keeps books signs in as a
|
|
87
|
+
// person; what installs and operates connects as the owner of the database,
|
|
88
|
+
// to whom no policy applies, and a reader of the log should not have to
|
|
89
|
+
// know which commands are which.
|
|
90
|
+
note(dim('Connected as the owner of the database: installing and operating, not keeping books. Row level security does not apply to this connection.'));
|
|
91
|
+
return { db, connection };
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EACL,UAAU,EACV,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,MAAM,EACN,yBAAyB,EACzB,aAAa,EACb,cAAc,EACd,cAAc,EACd,OAAO,GAGR,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAkB,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAEpC,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,QAAQ;IACR,aAAa;IACb,WAAW;IACX,aAAa;IACb,cAAc;IACd,kBAAkB;CACV,CAAC;AA+BX,wEAAwE;AACxE,MAAM,CAAC,MAAM,YAAY,GAAU,KAAK,EAAE,KAAK,EAAE,EAAE;IACjD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;QAChC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF,mEAAmE;AACnE,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAgB,EAChB,OAAuB;IAEvB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,aAAa,EAAE,CAAC;IAE3D,MAAM,gBAAgB,GAAG,UAAU,CAAC,IAAI,EAAE,cAAc,CAAC,IAAI,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACnF,MAAM,cAAc,GAAG,UAAU,CAAC,IAAI,EAAE,kBAAkB,CAAC,IAAI,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAEzF,IAAI,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAEtF,IAAI,UAAU,GACZ,cAAc,CAAC,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QAC/C,cAAc,CAAC,gBAAgB,CAAC;QAChC,cAAc,CAAC,KAAK,CAAC,CAAC;IAExB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAE7C,IAAI,KAAK,KAAK,SAAS,IAAI,UAAU,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC5E,MAAM,QAAQ,GACZ,UAAU,CAAC,IAAI,EAAE,aAAa,CAAC;YAC/B,GAAG,CAAC,kBAAkB,CAAC;YACvB,CAAC,WAAW;gBACV,CAAC,CAAC,MAAM,SAAS,CAAC,iCAAiC,UAAU,GAAG,CAAC;gBACjE,CAAC,CAAC,SAAS,CAAC,CAAC;QACjB,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,mBAAmB,CAAC,uBAAuB,EAAE,2BAA2B,CAAC,CAAC;QACtF,CAAC;QACD,0EAA0E;QAC1E,2EAA2E;QAC3E,wEAAwE;QACxE,wEAAwE;QACxE,yCAAyC;QACzC,KAAK,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;QACzF,IAAI,CAAC,GAAG,CAAC,mBAAmB,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,uEAAuE;IACvE,0EAA0E;IAC1E,yEAAyE;IACzE,8DAA8D;IAC9D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,mBAAmB,CAC3B,gCAAgC,EAChC,gEAAgE,CACjE,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAC5B,6EAA6E,CAC9E,CAAC;QACF,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,UAAU,CAClB,+EAA+E,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CACvG,CAAC;QACJ,CAAC;QACD,KAAK,GAAG,MAAM,CAAC;QACf,UAAU,GAAG,UAAU,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,WAAW,GACf,gBAAgB,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAE1F,OAAO;QACL,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC;QACrB,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpD,CAAC;AACJ,CAAC;AAOD,6CAA6C;AAC7C,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAgB,EAChB,OAAuB;IAEvB,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1D,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAChE,sEAAsE;IACtE,4EAA4E;IAC5E,wEAAwE;IACxE,iCAAiC;IACjC,IAAI,CAAC,GAAG,CAAC,4IAA4I,CAAC,CAAC,CAAC;IACxJ,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;AAC5B,CAAC"}
|
package/dist/doctor.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ekwo doctor` — the checks worth running on a live installation.
|
|
3
|
+
*
|
|
4
|
+
* Each one is something that is true of a healthy database and that nothing
|
|
5
|
+
* in the schema can enforce on its own: a table someone added without row
|
|
6
|
+
* level security, a migration that never landed, a membership row pointing at
|
|
7
|
+
* a user who has since been deleted, a bank statement whose declared closing
|
|
8
|
+
* balance does not match its lines.
|
|
9
|
+
*
|
|
10
|
+
* The doctor reads and reports. It never repairs: the fix for a missing
|
|
11
|
+
* policy is a migration, and the fix for an orphaned membership is a decision
|
|
12
|
+
* about who should have access, not a delete the installer guesses at.
|
|
13
|
+
*/
|
|
14
|
+
import { type ExpectedObjects } from './inventory.js';
|
|
15
|
+
import type { Migration } from './migrations.js';
|
|
16
|
+
import type { SqlClient } from './sql.js';
|
|
17
|
+
export type Severity = 'ok' | 'warning' | 'problem';
|
|
18
|
+
export interface Check {
|
|
19
|
+
name: string;
|
|
20
|
+
severity: Severity;
|
|
21
|
+
summary: string;
|
|
22
|
+
/** Lines of evidence, printed under the summary. */
|
|
23
|
+
details?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* The check's own findings, whole, for `--json`. The printed form is a
|
|
26
|
+
* summary of this and a machine reading the report should not have to parse
|
|
27
|
+
* English back into a list.
|
|
28
|
+
*/
|
|
29
|
+
data?: Record<string, unknown>;
|
|
30
|
+
}
|
|
31
|
+
export interface DoctorReport {
|
|
32
|
+
checks: Check[];
|
|
33
|
+
problems: number;
|
|
34
|
+
warnings: number;
|
|
35
|
+
}
|
|
36
|
+
export interface DoctorOptions {
|
|
37
|
+
/**
|
|
38
|
+
* The inventory to compare the catalogue against. Defaults to the one this
|
|
39
|
+
* CLI ships; a test passes its own to describe a schema that is not this
|
|
40
|
+
* release's.
|
|
41
|
+
*/
|
|
42
|
+
expected?: ExpectedObjects;
|
|
43
|
+
}
|
|
44
|
+
export declare function doctor(db: SqlClient, migrations: Migration[], options?: DoctorOptions): Promise<DoctorReport>;
|
|
45
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAOL,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,CAAC;AAEpD,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,wBAAsB,MAAM,CAC1B,EAAE,EAAE,SAAS,EACb,UAAU,EAAE,SAAS,EAAE,EACvB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA0BvB"}
|