ekwo-os 0.6.0 → 0.7.0
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 +111 -28
- package/dist/assets/expected-objects.json +2 -2
- package/dist/assets/migrations/20260922115309_an_installation_without_a_country.sql +24 -0
- package/dist/assets/migrations/20260922120418_import_already_done_says_what.sql +284 -0
- package/dist/assets/migrations/20260922124012_schema_version_0_7_0.sql +40 -0
- package/dist/auth.d.ts +17 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +24 -6
- package/dist/auth.js.map +1 -1
- package/dist/bootstrap.d.ts +17 -0
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +29 -8
- package/dist/bootstrap.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +26 -6
- package/dist/cli.js.map +1 -1
- package/dist/commands/company.d.ts +14 -2
- package/dist/commands/company.d.ts.map +1 -1
- package/dist/commands/company.js +185 -8
- package/dist/commands/company.js.map +1 -1
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/commands/import.js +25 -6
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +132 -123
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/company-choices.d.ts +66 -0
- package/dist/company-choices.d.ts.map +1 -0
- package/dist/company-choices.js +165 -0
- package/dist/company-choices.js.map +1 -0
- package/dist/config.d.ts +11 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -6
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/registry.d.ts +3 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +1 -1
- package/package.json +3 -3
- package/schema/output.1.json +73 -24
package/README.md
CHANGED
|
@@ -6,13 +6,17 @@ books: the schema, the chart of accounts, the VAT codes, the first
|
|
|
6
6
|
administrator, the first company and its first financial year.
|
|
7
7
|
|
|
8
8
|
```sh
|
|
9
|
-
npx ekwo-os init
|
|
9
|
+
npx -y ekwo-os@latest init
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
The package is `ekwo-os` and the command it installs is `ekwo`:
|
|
13
|
-
<command>` runs it without installing anything, and
|
|
14
|
-
`npm install -g ekwo-os` every example below that starts with `ekwo `
|
|
15
|
-
written.
|
|
12
|
+
The package is `ekwo-os` and the command it installs is `ekwo`:
|
|
13
|
+
`npx -y ekwo-os@latest <command>` runs it without installing anything, and
|
|
14
|
+
after `npm install -g ekwo-os` every example below that starts with `ekwo `
|
|
15
|
+
works as written. Keep the version in the command: run from inside a clone of
|
|
16
|
+
the Ekwo repository, a bare `npx ekwo-os` finds the workspace package of the
|
|
17
|
+
same name, which links no command, and answers `ekwo: command not found`. With
|
|
18
|
+
`@latest`, `npx` fetches the published CLI wherever it is started; the clone's
|
|
19
|
+
own is `node packages/cli/dist/bin.js`, after `npm run build`.
|
|
16
20
|
|
|
17
21
|
You need Node 20 or later. That is the whole list. The Supabase CLI is not
|
|
18
22
|
required — this talks to Postgres directly — and Docker is not required
|
|
@@ -26,9 +30,11 @@ either.
|
|
|
26
30
|
2. **Copy two things** from the dashboard:
|
|
27
31
|
- Project Settings → Database → **Connection string** (URI). It contains
|
|
28
32
|
your database password.
|
|
29
|
-
- Project Settings → API →
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
- Project Settings → API Keys → the **secret key** (`sb_secret_…`), and the
|
|
34
|
+
**Project URL**. A project created before the new keys has the legacy
|
|
35
|
+
**`service_role` key** instead, and it works the same. These are used
|
|
36
|
+
once, to create the first administrator in your own Supabase Auth, and
|
|
37
|
+
are never written to disk.
|
|
32
38
|
|
|
33
39
|
**Take the pooler string, not the direct one, unless you know you have
|
|
34
40
|
IPv6.** The direct host `db.<ref>.supabase.co` resolves to an IPv6 address
|
|
@@ -48,7 +54,7 @@ either.
|
|
|
48
54
|
3. **Run the installer.**
|
|
49
55
|
|
|
50
56
|
```sh
|
|
51
|
-
npx ekwo-os init
|
|
57
|
+
npx -y ekwo-os@latest init
|
|
52
58
|
```
|
|
53
59
|
|
|
54
60
|
It asks for the connection string, the country, the chart of accounts and
|
|
@@ -71,7 +77,7 @@ either.
|
|
|
71
77
|
Everything above in one non-interactive line:
|
|
72
78
|
|
|
73
79
|
```sh
|
|
74
|
-
npx ekwo-os init \
|
|
80
|
+
npx -y ekwo-os@latest init \
|
|
75
81
|
--db-url "postgresql://postgres.YOURREF:PASSWORD@aws-1-eu-west-3.pooler.supabase.com:5432/postgres" \
|
|
76
82
|
--supabase-url "https://YOURREF.supabase.co" \
|
|
77
83
|
--service-role-key "$SUPABASE_SERVICE_ROLE_KEY" \
|
|
@@ -117,6 +123,52 @@ in `defaults.fiscal_year_default`; one that names none — the United Kingdom's,
|
|
|
117
123
|
where a company's year ends on the accounting reference date it chose — asks
|
|
118
124
|
for the day.
|
|
119
125
|
|
|
126
|
+
`ekwo company new` asks the same questions about every other company, and
|
|
127
|
+
refuses the same way.
|
|
128
|
+
|
|
129
|
+
## Several countries in one installation: `init --no-company`
|
|
130
|
+
|
|
131
|
+
An installation is not in a country; its companies are. `ekwo init` loads every
|
|
132
|
+
pack of the release whatever `--country` says, so one installation keeps the
|
|
133
|
+
books of companies in as many countries as it holds packs. When there is no
|
|
134
|
+
"first company" to name — a group, a firm, a holding with subsidiaries abroad —
|
|
135
|
+
install without one, then create each company in its own country:
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
npx -y ekwo-os@latest init --no-company \
|
|
139
|
+
--db-url "$EKWO_DB_URL" --supabase-url "https://YOURREF.supabase.co" \
|
|
140
|
+
--service-role-key "$SUPABASE_SERVICE_ROLE_KEY" \
|
|
141
|
+
--org "My Group" --admin-email "you@example.com" --yes
|
|
142
|
+
|
|
143
|
+
ekwo company new "My Company Belgium" --country BE --chart default --language nl --yes
|
|
144
|
+
ekwo company new "My Company France" --country FR --language fr --yes
|
|
145
|
+
ekwo company list
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`--no-company` runs the migrations, the seeds of every pack, the modules, the
|
|
149
|
+
first administrator, `init_instance()` and `claim_instance_admin()`, and
|
|
150
|
+
nothing else. The instance row records no country. A flag that only describes
|
|
151
|
+
a company — `--country`, `--company`, `--chart`, `--language`, `--currency`,
|
|
152
|
+
`--fiscal-year`, `--fiscal-year-start`, `--vat-period`, `--filing-period`,
|
|
153
|
+
`--iban`, `--bic`, `--bank-name` — is refused with it, exit code 2, before the
|
|
154
|
+
database is touched: it would describe nothing.
|
|
155
|
+
|
|
156
|
+
**`ekwo company new` is `create_company()`**, the function the `create_company`
|
|
157
|
+
tool of the MCP server calls: the country pack copied in, the first financial
|
|
158
|
+
year opened, the administrator its first owner. It is called as an
|
|
159
|
+
administrator of the installation — `--as-user`, or the only one when there is
|
|
160
|
+
exactly one — so the database judges that person exactly as it judges the tool:
|
|
161
|
+
anybody else is refused, `not_instance_admin`, exit code 3. Before the call,
|
|
162
|
+
the CLI asks what `ekwo init` asks about its first company, from the packs the
|
|
163
|
+
installation holds, and refuses the same way off a terminal: no country without
|
|
164
|
+
`--country`, and `--chart`, `--language` and `--fiscal-year-start` wherever the
|
|
165
|
+
pack offers a choice. `--currency` and `--fiscal-year` override the pack and
|
|
166
|
+
this year.
|
|
167
|
+
|
|
168
|
+
Without `--no-company`, `ekwo init` does what it always did, and the installation
|
|
169
|
+
takes more companies later the same way. Neither writes a country into
|
|
170
|
+
`ekwo.json`: see below.
|
|
171
|
+
|
|
120
172
|
## Where table access comes from
|
|
121
173
|
|
|
122
174
|
**The schema grants its own rights.** Every table, view and function of Ekwo
|
|
@@ -222,7 +274,7 @@ and read by a person.
|
|
|
222
274
|
| 2 | Applies every reference seed of `supabase/seed/`, in file-name order: `00_currencies.sql`, `00_territories.sql`, `05_framework_generic.sql`, then one `<n>_pack_<cc>.sql` per country pack, in the order of the number each pack declares | The currencies, the territories the tax rules name, the country-less financial statements every chart falls back on, and every country pack of the release — so a company in any of them can be created later without installing anything. They are exactly the seeds `supabase/config.toml` lists (a list `ekwo pack build` writes from `packs/`), so `supabase db push` installs the same set; a test compares both paths row by row. `90_demo_company.sql` is sample data and is never applied here |
|
|
223
275
|
| 3 | Creates the first administrator through the Supabase Auth admin API | See below: a database connection cannot be a signed-in user |
|
|
224
276
|
| 4 | `init_instance()`, `claim_instance_admin()`, the company, `company_members` as owner, `install_country_template()`, the first financial year, and the bank account when an IBAN was given | The six steps of the root README, in the same order, plus the one thing nobody can derive |
|
|
225
|
-
| 5 | Writes `ekwo.json` |
|
|
277
|
+
| 5 | Writes `ekwo.json` | The installation: project URL and schema version. Nothing else, ever — no country, since each company carries its own. A file written by 0.6 or earlier also names a country; it is still read, and the key is taken for nothing |
|
|
226
278
|
| 6 | Asks whether to register with Ekwo | The default answer is no, and no is a supported answer forever |
|
|
227
279
|
|
|
228
280
|
Every step checks before it acts. Running `ekwo init` twice on the same
|
|
@@ -250,7 +302,7 @@ instead if the account already exists, and no key is needed.
|
|
|
250
302
|
|
|
251
303
|
| Command | What it does |
|
|
252
304
|
|---|---|
|
|
253
|
-
| `ekwo init` | The whole installation, interactive or not: the socle's migrations, the reference seeds, then the modules', as `ekwo migrate` applies them. |
|
|
305
|
+
| `ekwo init` | The whole installation, interactive or not: the socle's migrations, the reference seeds, then the modules', as `ekwo migrate` applies them. `--no-company` stops before the first company: see [several countries](#several-countries-in-one-installation-init---no-company). |
|
|
254
306
|
| `ekwo migrate` | Applies the migrations this release adds, after showing the gap — the socle's, then the modules'. Re-applies the reference seeds, which are idempotent. `--no-modules` leaves the modules alone. |
|
|
255
307
|
| `ekwo status` | Schema version installed against available, pending migrations, the instance, its administrators, the country packs it holds and, per company, the pack version it copied. Exits 1 when something is pending. |
|
|
256
308
|
| `ekwo doctor` | Every object this release defines and every privilege it grants, against what the database holds; row level security on every table, a policy on every protected table, no pending migration, no membership pointing at a deleted user, every company with a bank account, statements that tie to their lines, posted entries that balance. Exits 1 on a problem, 0 on warnings. |
|
|
@@ -258,7 +310,7 @@ instead if the account already exists, and no key is needed.
|
|
|
258
310
|
| `ekwo unregister` | Opt back out. Clears the address and the date on the instance row. |
|
|
259
311
|
| `ekwo demo` | Loads the sample company. Fictional data, explicit request only. |
|
|
260
312
|
| `ekwo module` | What is installed beside the socle, applies a module's migrations and its country seeds, and turns one on or off for a company. |
|
|
261
|
-
| `ekwo company` | One company leaves an installation with its books — `export` writes an archive anybody can read, as a member under row level security — and arrives in another one alive: `import` takes it in whole or not at all. |
|
|
313
|
+
| `ekwo company` | `new` creates a company in its own country, through `create_company()`, and `list` shows the companies held here. One company leaves an installation with its books — `export` writes an archive anybody can read, as a member under row level security — and arrives in another one alive: `import` takes it in whole or not at all. |
|
|
262
314
|
| `ekwo pack` | Compiles a country pack into its seed, and refuses a seed that is no longer the output of its pack. Runs in a checkout of the repository only. |
|
|
263
315
|
| `ekwo login` | Signs in to an instance as yourself and keeps the session, in your own configuration directory. See [acting as a person](#acting-as-a-person-login-use-whoami). |
|
|
264
316
|
| `ekwo logout` | Ends that session, here and on the instance. |
|
|
@@ -515,7 +567,7 @@ source, and nothing is posted while an account has no answer:
|
|
|
515
567
|
```bash
|
|
516
568
|
ekwo import fec 123456789FEC20251231.txt --dry-run --open-years --save-mapping map.json
|
|
517
569
|
# read, propose a correspondence, rehearse the import in the database, take it back
|
|
518
|
-
$EDITOR map.json # answer what is null
|
|
570
|
+
$EDITOR map.json # answer what is null — read `suggested` — correct what is wrong
|
|
519
571
|
ekwo import fec 123456789FEC20251231.txt --mapping map.json --open-years
|
|
520
572
|
ekwo import trial-balance balance.csv --opening-date 2026-01-01 --dry-run --save-mapping map.json
|
|
521
573
|
ekwo import journal-items items.csv accounts.csv partners.csv --dry-run --save-mapping map.json
|
|
@@ -540,23 +592,33 @@ official page and state.
|
|
|
540
592
|
|
|
541
593
|
**The correspondence is yours.** Every account of the old chart has to become
|
|
542
594
|
an account of the company's chart, and every old journal a journal of the
|
|
543
|
-
company. The
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
595
|
+
company. The codes give a candidate — the same code, the same digits without
|
|
596
|
+
the zeros a chart pads with (`411` and `411000`), or the account whose digits
|
|
597
|
+
are the longest beginning of the old code, three at least (`401ACME` and
|
|
598
|
+
`401000`); a tie is no answer — and what the files say of the old account —
|
|
599
|
+
the type its export gives it, its name, the side of its balance — is held
|
|
600
|
+
against the type of the candidate in the chart, because two charts give the
|
|
601
|
+
same digits to different things. Only the same code, not contradicted, is
|
|
602
|
+
`exact`. Anything else is `suggested`, with its reason, and waits for you; a
|
|
603
|
+
candidate the files contradict is dropped for the one account of the chart of
|
|
604
|
+
the kind they say. `--dry-run` prints the lines to read first, each with its
|
|
605
|
+
reason, and `--save-mapping` writes the correspondence as JSON:
|
|
548
606
|
|
|
549
607
|
```json
|
|
550
608
|
{
|
|
551
609
|
"version": 1,
|
|
552
610
|
"source": "fec",
|
|
553
|
-
"accounts": { "411000": "411000", "401ACME":
|
|
554
|
-
"journals": { "VE": "SAL", "AN": "@opening", "BQ1": "MISC" }
|
|
611
|
+
"accounts": { "411000": "411000", "401ACME": null, "471200": null },
|
|
612
|
+
"journals": { "VE": "SAL", "AN": "@opening", "BQ1": "MISC" },
|
|
613
|
+
"suggested": { "401ACME": { "target": "401000", "reason": "the longest beginning of the code the chart has; …" } }
|
|
555
614
|
}
|
|
556
615
|
```
|
|
557
616
|
|
|
558
617
|
and `--mapping` gives it back: what it answers wins over the proposal, so the
|
|
559
|
-
second run posts what the first one showed. A
|
|
618
|
+
second run posts what the first one showed. A suggestion is confirmed by
|
|
619
|
+
writing its code under `accounts`; `--accept-suggestions` takes all of them
|
|
620
|
+
once you have read them. Nothing is posted while one the books use is only
|
|
621
|
+
suggested. A journal mapped to `@opening`
|
|
560
622
|
becomes the opening entry of its year instead of ordinary entries — the
|
|
561
623
|
*à-nouveaux* of a FEC, typically. A journal whose code is the one the pack
|
|
562
624
|
opens years on is proposed as `@opening` on its own; `*` stands for entries
|
|
@@ -580,7 +642,7 @@ dry run reads the file and asks nothing: a statement books nothing anyway.
|
|
|
580
642
|
What else to know:
|
|
581
643
|
|
|
582
644
|
- **Refused before the database is asked**, and listed under `refusals` by a
|
|
583
|
-
dry run: an account or a journal with no answer, books whose reader found
|
|
645
|
+
dry run: an account or a journal with no answer or only a suggestion, books whose reader found
|
|
584
646
|
something that does not add up (an entry that does not balance, a line of a
|
|
585
647
|
draft entry), a currency the files name that is not the company's.
|
|
586
648
|
- **The numbers** are drawn by the journal each entry goes to; the old number
|
|
@@ -592,7 +654,8 @@ What else to know:
|
|
|
592
654
|
statements, and no box of a VAT return. A period kept elsewhere was declared
|
|
593
655
|
from where it was kept.
|
|
594
656
|
- **The same files twice are refused** (`import_already_done`): `book_imports`
|
|
595
|
-
keeps the checksum of what each import read
|
|
657
|
+
keeps the checksum of what each import read, and the refusal says which
|
|
658
|
+
files, when, and what that import wrote.
|
|
596
659
|
- **Dates and encodings are said, never guessed**: `--encoding` for a file
|
|
597
660
|
that is not UTF-8, `--date-order` for a report that writes dates in digits.
|
|
598
661
|
- **Reconciliation marks are read and not re-applied yet**: the matching of an
|
|
@@ -631,9 +694,23 @@ them as history it has no file for.
|
|
|
631
694
|
|
|
632
695
|
## `ekwo company`
|
|
633
696
|
|
|
634
|
-
A firm keeps several companies in one installation,
|
|
635
|
-
|
|
636
|
-
|
|
697
|
+
A firm keeps several companies in one installation, each in its own country,
|
|
698
|
+
and each of them belongs to somebody. `new` creates one and `list` shows them —
|
|
699
|
+
see [several countries](#several-countries-in-one-installation-init---no-company):
|
|
700
|
+
|
|
701
|
+
```sh
|
|
702
|
+
ekwo company new "My Company Belgium" --country BE --chart default --language fr
|
|
703
|
+
ekwo company new "My Company France" --country FR --language fr
|
|
704
|
+
ekwo company list # name, country, currency, language, chart, pack, members
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
`company new --json` answers the company (`id`, `country`, `currency`,
|
|
708
|
+
`language`, `chart`, `packVersion`), its first financial year and its owner;
|
|
709
|
+
`company list --json` answers `companies`, one per company. Both shapes are
|
|
710
|
+
under `$defs/data` of the output schema, and the exit codes are the ones every
|
|
711
|
+
command has: 2 for a missing answer, 3 when the database refuses.
|
|
712
|
+
|
|
713
|
+
The two commands below are how a company leaves, and arrives somewhere else.
|
|
637
714
|
|
|
638
715
|
```sh
|
|
639
716
|
ekwo company export "My Company" --out ./my-company # manifest.json + data/<schema>.<table>.jsonl
|
|
@@ -810,7 +887,7 @@ Every command takes the connection flags:
|
|
|
810
887
|
| `--db-password <pw>` | Database password. Prompted, masked, when omitted. |
|
|
811
888
|
| `--db-region <region>` | With `--project-ref`, the session pooler in that region. Both generation prefixes are tried and the one that answers is kept. |
|
|
812
889
|
| `--supabase-url <url>` | `https://<ref>.supabase.co`. Needed only to create a user. |
|
|
813
|
-
| `--service-role-key <key>` | Needed only to create a user. |
|
|
890
|
+
| `--service-role-key <key>` | Needed only to create a user. Either form Supabase issues: a secret key, `sb_secret_…`, sent on the `apikey` header alone because it is not a JWT, or the legacy `service_role` JWT, sent on `apikey` and as a Bearer as before. |
|
|
814
891
|
| `--yes`, `-y` | Never ask a question. Everything must come from flags or the environment. |
|
|
815
892
|
|
|
816
893
|
`--project-ref` with `--db-password` and `--db-region` builds the session
|
|
@@ -845,6 +922,12 @@ dashboard under Connect → Session pooler, is the form that is never derived.
|
|
|
845
922
|
| `--register` | Register without being asked. `--register-email` sets the address. |
|
|
846
923
|
| `--registry-url <url>` | Where the registration is announced. |
|
|
847
924
|
| `--no-modules` | Leave the modules out. By default `init` installs them, as `ekwo migrate` does — empty schemas until a company enables one. |
|
|
925
|
+
| `--no-company` | Install without a company: schema, every pack, the modules, the first administrator, and no country on the instance row. The flags that only describe a company are refused with it. Then `ekwo company new`, once per company. |
|
|
926
|
+
|
|
927
|
+
`ekwo company new <name>` takes `--country`, `--chart`, `--language`,
|
|
928
|
+
`--currency`, `--fiscal-year` and `--fiscal-year-start` as `init` does, and
|
|
929
|
+
`--as-user <uuid>`: the administrator of the installation it is created as,
|
|
930
|
+
who becomes its owner — the only one, when there is exactly one.
|
|
848
931
|
|
|
849
932
|
Every command takes `--json`; see [what a command answers](#what-a-command-answers---json-and-the-exit-codes).
|
|
850
933
|
`ekwo migrate` takes `--skip-seeds`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- Ekwo OS — an installation is not in a country; its companies are.
|
|
2
|
+
--
|
|
3
|
+
-- `instance.country` was `not null` because the installation used to be set up
|
|
4
|
+
-- *for* one country: `ekwo init` created the first company in the same run and
|
|
5
|
+
-- wrote its country on the instance row. It never meant more than that. The
|
|
6
|
+
-- seeds of every pack are loaded whatever it says, `create_company()` takes a
|
|
7
|
+
-- country per company, and nothing in the schema reads the column — a firm
|
|
8
|
+
-- keeping the books of companies in two countries has had one installation
|
|
9
|
+
-- for both since the first release.
|
|
10
|
+
--
|
|
11
|
+
-- `ekwo init --no-company` installs the schema, the packs and the first
|
|
12
|
+
-- administrator and creates no company, so there is no country to write down,
|
|
13
|
+
-- and inventing one would be a default nobody chose. The column becomes
|
|
14
|
+
-- nullable. The format check stays: a country, when there is one, is still two
|
|
15
|
+
-- capital letters, and a null passes a check by definition.
|
|
16
|
+
--
|
|
17
|
+
-- `init_instance()` is unchanged: `upper(null)` is null, and the row now takes
|
|
18
|
+
-- it. An installation set up with a company keeps the country of that company,
|
|
19
|
+
-- as before.
|
|
20
|
+
|
|
21
|
+
alter table instance alter column country drop not null;
|
|
22
|
+
|
|
23
|
+
comment on column instance.country is
|
|
24
|
+
'The country of the first company, when `ekwo init` created one with the installation. Null for an installation set up without a company. Informative: every company carries its own country, and nothing reads this one to decide anything.';
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
-- Ekwo OS — a second import of the same files says what the first one was.
|
|
2
|
+
--
|
|
3
|
+
-- `import_books()` refuses files it has already imported, by their checksum,
|
|
4
|
+
-- and the refusal said when and then "(% entries, % to %)". For a trial
|
|
5
|
+
-- balance — the first thing most people import, and an import with no entry
|
|
6
|
+
-- at all — that read "0 entries, — to —": true, and no help to somebody
|
|
7
|
+
-- trying to remember what they did. The row in `book_imports` knows more: the
|
|
8
|
+
-- file names, the source, the time, and the number of the opening entry.
|
|
9
|
+
--
|
|
10
|
+
-- So the refusal names them: which files, read as which source, imported when
|
|
11
|
+
-- (to the minute, in UTC, since a person may import twice in one day), and
|
|
12
|
+
-- what that import wrote — its entries with their first and last number, its
|
|
13
|
+
-- opening entry by number, or both. The function is otherwise the one of
|
|
14
|
+
-- `20260922081645_books_taken_over_from_an_export`, republished whole because
|
|
15
|
+
-- a function body cannot be patched.
|
|
16
|
+
|
|
17
|
+
create or replace function import_books(
|
|
18
|
+
p_company_id uuid,
|
|
19
|
+
p_books jsonb,
|
|
20
|
+
p_dry_run boolean default false,
|
|
21
|
+
p_open_years boolean default false,
|
|
22
|
+
p_allow_result_accounts boolean default false
|
|
23
|
+
)
|
|
24
|
+
returns jsonb
|
|
25
|
+
language plpgsql
|
|
26
|
+
volatile
|
|
27
|
+
security invoker
|
|
28
|
+
as $$
|
|
29
|
+
declare
|
|
30
|
+
v_checksum text := p_books ->> 'checksum';
|
|
31
|
+
v_source text := p_books ->> 'source';
|
|
32
|
+
v_previous book_imports;
|
|
33
|
+
v_result jsonb;
|
|
34
|
+
v_contacts jsonb := '{}'::jsonb;
|
|
35
|
+
v_contact jsonb;
|
|
36
|
+
v_contact_id uuid;
|
|
37
|
+
v_created integer := 0;
|
|
38
|
+
v_found integer := 0;
|
|
39
|
+
v_entry jsonb;
|
|
40
|
+
v_draft entries;
|
|
41
|
+
v_journal uuid;
|
|
42
|
+
v_date date;
|
|
43
|
+
v_missing text;
|
|
44
|
+
v_years jsonb := '[]'::jsonb;
|
|
45
|
+
v_year uuid;
|
|
46
|
+
v_entries integer := 0;
|
|
47
|
+
v_lines integer := 0;
|
|
48
|
+
v_first text;
|
|
49
|
+
v_last text;
|
|
50
|
+
v_opening jsonb := p_books -> 'opening';
|
|
51
|
+
v_opening_id uuid;
|
|
52
|
+
v_opening_no text;
|
|
53
|
+
v_debit numeric := 0;
|
|
54
|
+
v_credit numeric := 0;
|
|
55
|
+
v_journals jsonb;
|
|
56
|
+
begin
|
|
57
|
+
if not exists (select 1 from companies c where c.id = p_company_id) then
|
|
58
|
+
raise exception 'unknown_company: %', p_company_id using errcode = 'no_data_found';
|
|
59
|
+
end if;
|
|
60
|
+
-- Row level security is what refuses; this is what says why.
|
|
61
|
+
if not coalesce(is_installer(), false) then
|
|
62
|
+
if not coalesce(has_capability(p_company_id, 'entries.write'), false)
|
|
63
|
+
or not coalesce(has_capability(p_company_id, 'entries.post'), false) then
|
|
64
|
+
raise exception 'not_allowed: importing books into this company needs entries.write and entries.post'
|
|
65
|
+
using errcode = '42501';
|
|
66
|
+
end if;
|
|
67
|
+
end if;
|
|
68
|
+
if v_source is null or v_checksum is null then
|
|
69
|
+
raise exception 'invalid_books: the books name no source or no checksum — expected them as the importer builds them';
|
|
70
|
+
end if;
|
|
71
|
+
if jsonb_typeof(coalesce(p_books -> 'entries', '[]'::jsonb)) <> 'array' then
|
|
72
|
+
raise exception 'invalid_books: entries must be a list';
|
|
73
|
+
end if;
|
|
74
|
+
if jsonb_array_length(coalesce(p_books -> 'entries', '[]'::jsonb)) = 0
|
|
75
|
+
and (v_opening is null or jsonb_typeof(v_opening) = 'null') then
|
|
76
|
+
raise exception 'import_empty: the files hold no entry and no balance; there is nothing to import';
|
|
77
|
+
end if;
|
|
78
|
+
|
|
79
|
+
select * into v_previous from book_imports b
|
|
80
|
+
where b.company_id = p_company_id and b.checksum = v_checksum;
|
|
81
|
+
if found then
|
|
82
|
+
raise exception 'import_already_done: % (%) was imported on % UTC: %. Importing it again would count every amount twice',
|
|
83
|
+
coalesce(nullif(array_to_string(v_previous.file_names, ', '), ''), 'the same file'),
|
|
84
|
+
v_previous.source,
|
|
85
|
+
to_char(v_previous.created_at at time zone 'UTC', 'YYYY-MM-DD HH24:MI'),
|
|
86
|
+
concat_ws(' and ',
|
|
87
|
+
case when v_previous.entry_count > 0 then
|
|
88
|
+
v_previous.entry_count || case when v_previous.entry_count = 1 then ' entry' else ' entries' end
|
|
89
|
+
|| coalesce(', numbered ' || v_previous.first_number
|
|
90
|
+
|| case when v_previous.last_number is distinct from v_previous.first_number
|
|
91
|
+
then ' to ' || v_previous.last_number else '' end, '')
|
|
92
|
+
end,
|
|
93
|
+
case when v_previous.opening_number is not null then
|
|
94
|
+
'the opening entry ' || v_previous.opening_number
|
|
95
|
+
end,
|
|
96
|
+
v_previous.line_count || case when v_previous.line_count = 1 then ' line' else ' lines' end)
|
|
97
|
+
using errcode = '23505';
|
|
98
|
+
end if;
|
|
99
|
+
|
|
100
|
+
begin
|
|
101
|
+
-- 1. The years. Each date that falls in none is refused by name, or opened
|
|
102
|
+
-- when the caller asked for it.
|
|
103
|
+
for v_date in
|
|
104
|
+
select distinct d::date from (
|
|
105
|
+
select e ->> 'date' as d from jsonb_array_elements(coalesce(p_books -> 'entries', '[]'::jsonb)) e
|
|
106
|
+
union
|
|
107
|
+
select v_opening ->> 'date' where v_opening is not null and jsonb_typeof(v_opening) <> 'null'
|
|
108
|
+
) dates
|
|
109
|
+
where d is not null
|
|
110
|
+
order by 1
|
|
111
|
+
loop
|
|
112
|
+
if fiscal_year_at(p_company_id, v_date) is null then
|
|
113
|
+
if not p_open_years then
|
|
114
|
+
raise exception 'import_outside_fiscal_year: % falls in no fiscal year of this company. Open that year, or ask the import to open the years it needs',
|
|
115
|
+
v_date
|
|
116
|
+
using errcode = '55006';
|
|
117
|
+
end if;
|
|
118
|
+
v_year := import_fiscal_year_for(p_company_id, v_date);
|
|
119
|
+
select v_years || jsonb_build_object('name', f.name, 'start_date', f.start_date::text, 'end_date', f.end_date::text)
|
|
120
|
+
into v_years from fiscal_years f where f.id = v_year;
|
|
121
|
+
end if;
|
|
122
|
+
end loop;
|
|
123
|
+
|
|
124
|
+
-- 2. The parties: by the code the source gave them, then by their name,
|
|
125
|
+
-- or created. A party the file names once is still one party.
|
|
126
|
+
for v_contact in select value from jsonb_array_elements(coalesce(p_books -> 'contacts', '[]'::jsonb)) loop
|
|
127
|
+
v_contact_id := null;
|
|
128
|
+
if nullif(v_contact ->> 'auxiliary_code', '') is not null then
|
|
129
|
+
select c.id into v_contact_id from contacts c
|
|
130
|
+
where c.company_id = p_company_id and c.auxiliary_code = v_contact ->> 'auxiliary_code'
|
|
131
|
+
order by c.created_at limit 1;
|
|
132
|
+
end if;
|
|
133
|
+
if v_contact_id is null then
|
|
134
|
+
select c.id into v_contact_id from contacts c
|
|
135
|
+
where c.company_id = p_company_id and lower(c.name) = lower(v_contact ->> 'name')
|
|
136
|
+
order by c.created_at limit 1;
|
|
137
|
+
end if;
|
|
138
|
+
if v_contact_id is null then
|
|
139
|
+
insert into contacts (company_id, name, contact_type, auxiliary_code,
|
|
140
|
+
vat_number, registration_number, email, country)
|
|
141
|
+
values (p_company_id, v_contact ->> 'name',
|
|
142
|
+
coalesce(v_contact ->> 'contact_type', 'other')::contact_type,
|
|
143
|
+
nullif(v_contact ->> 'auxiliary_code', ''),
|
|
144
|
+
nullif(v_contact ->> 'vat_number', ''),
|
|
145
|
+
nullif(v_contact ->> 'registration_number', ''),
|
|
146
|
+
nullif(v_contact ->> 'email', ''),
|
|
147
|
+
nullif(upper(v_contact ->> 'country'), ''))
|
|
148
|
+
returning id into v_contact_id;
|
|
149
|
+
v_created := v_created + 1;
|
|
150
|
+
else
|
|
151
|
+
v_found := v_found + 1;
|
|
152
|
+
end if;
|
|
153
|
+
v_contacts := v_contacts || jsonb_build_object(v_contact ->> 'key', v_contact_id);
|
|
154
|
+
end loop;
|
|
155
|
+
|
|
156
|
+
-- 3. The accounts every line names, all of them, before anything is
|
|
157
|
+
-- written: one refusal that lists them is worth more than the first.
|
|
158
|
+
select string_agg(distinct code, ', ' order by code) into v_missing
|
|
159
|
+
from (
|
|
160
|
+
select l ->> 'account_code' as code
|
|
161
|
+
from jsonb_array_elements(coalesce(p_books -> 'entries', '[]'::jsonb)) e,
|
|
162
|
+
jsonb_array_elements(e -> 'lines') l
|
|
163
|
+
union
|
|
164
|
+
select l ->> 'account_code'
|
|
165
|
+
from jsonb_array_elements(coalesce(v_opening -> 'lines', '[]'::jsonb)) l
|
|
166
|
+
) wanted
|
|
167
|
+
where not exists (select 1 from accounts a where a.company_id = p_company_id and a.code = wanted.code);
|
|
168
|
+
if v_missing is not null then
|
|
169
|
+
raise exception 'unknown_account: % % not in the chart of this company. Map each to an account of the chart',
|
|
170
|
+
v_missing, case when v_missing like '%,%' then 'are' else 'is' end
|
|
171
|
+
using errcode = 'no_data_found';
|
|
172
|
+
end if;
|
|
173
|
+
|
|
174
|
+
-- 4. The entries, each a draft and then posted by post_entry().
|
|
175
|
+
for v_entry in select value from jsonb_array_elements(coalesce(p_books -> 'entries', '[]'::jsonb)) loop
|
|
176
|
+
select j.id into v_journal from journals j
|
|
177
|
+
where j.company_id = p_company_id and j.code = v_entry ->> 'journal_code';
|
|
178
|
+
if v_journal is null then
|
|
179
|
+
raise exception 'unknown_journal: % is not a journal of this company', v_entry ->> 'journal_code'
|
|
180
|
+
using errcode = 'no_data_found';
|
|
181
|
+
end if;
|
|
182
|
+
|
|
183
|
+
insert into entries (company_id, journal_id, entry_date, number, reference, description, state, currency_code)
|
|
184
|
+
select p_company_id, v_journal, (v_entry ->> 'date')::date,
|
|
185
|
+
nullif(v_entry ->> 'number', ''),
|
|
186
|
+
nullif(v_entry ->> 'reference', ''),
|
|
187
|
+
nullif(v_entry ->> 'description', ''),
|
|
188
|
+
'draft', c.currency_code
|
|
189
|
+
from companies c where c.id = p_company_id
|
|
190
|
+
returning * into v_draft;
|
|
191
|
+
|
|
192
|
+
insert into entry_lines (entry_id, company_id, account_id, sequence, name, debit, credit,
|
|
193
|
+
contact_id, currency_code, amount_currency, date_maturity)
|
|
194
|
+
select v_draft.id, p_company_id, a.id, (l.ordinality * 10)::integer,
|
|
195
|
+
nullif(l.value ->> 'label', ''),
|
|
196
|
+
coalesce((l.value ->> 'debit')::numeric, 0),
|
|
197
|
+
coalesce((l.value ->> 'credit')::numeric, 0),
|
|
198
|
+
case when l.value ->> 'contact_key' is null then null
|
|
199
|
+
else (v_contacts ->> (l.value ->> 'contact_key'))::uuid end,
|
|
200
|
+
nullif(l.value ->> 'currency_code', ''),
|
|
201
|
+
nullif(l.value ->> 'amount_currency', '')::numeric,
|
|
202
|
+
nullif(l.value ->> 'date_maturity', '')::date
|
|
203
|
+
from jsonb_array_elements(v_entry -> 'lines') with ordinality l
|
|
204
|
+
join accounts a on a.company_id = p_company_id and a.code = l.value ->> 'account_code';
|
|
205
|
+
|
|
206
|
+
v_draft := post_entry(v_draft.id);
|
|
207
|
+
v_entries := v_entries + 1;
|
|
208
|
+
v_lines := v_lines + jsonb_array_length(v_entry -> 'lines');
|
|
209
|
+
v_debit := v_debit + v_draft.total_debit;
|
|
210
|
+
v_credit := v_credit + v_draft.total_credit;
|
|
211
|
+
v_first := coalesce(v_first, v_draft.number);
|
|
212
|
+
v_last := v_draft.number;
|
|
213
|
+
end loop;
|
|
214
|
+
|
|
215
|
+
-- 5. The balances, as the opening entry of the year they open.
|
|
216
|
+
if v_opening is not null and jsonb_typeof(v_opening) <> 'null' then
|
|
217
|
+
v_year := fiscal_year_at(p_company_id, (v_opening ->> 'date')::date);
|
|
218
|
+
if (select f.start_date from fiscal_years f where f.id = v_year) <> (v_opening ->> 'date')::date then
|
|
219
|
+
raise exception 'opening_not_first_day: an opening balance is dated on the first day of a fiscal year, and % is not; the year it falls in starts on %',
|
|
220
|
+
v_opening ->> 'date', (select f.start_date from fiscal_years f where f.id = v_year);
|
|
221
|
+
end if;
|
|
222
|
+
v_opening_id := opening_balance(
|
|
223
|
+
p_company_id, v_year,
|
|
224
|
+
(select jsonb_agg(jsonb_build_object(
|
|
225
|
+
'account_code', l ->> 'account_code',
|
|
226
|
+
'debit', l ->> 'debit',
|
|
227
|
+
'credit', l ->> 'credit',
|
|
228
|
+
'label', coalesce(nullif(l ->> 'label', ''), 'Opening balance'),
|
|
229
|
+
'contact_id', case when l ->> 'contact_key' is null then null
|
|
230
|
+
else v_contacts ->> (l ->> 'contact_key') end))
|
|
231
|
+
from jsonb_array_elements(v_opening -> 'lines') l),
|
|
232
|
+
p_allow_result_accounts);
|
|
233
|
+
select e.number into v_opening_no from entries e where e.id = v_opening_id;
|
|
234
|
+
v_lines := v_lines + jsonb_array_length(v_opening -> 'lines');
|
|
235
|
+
end if;
|
|
236
|
+
|
|
237
|
+
select coalesce(jsonb_agg(jsonb_build_object('journal_code', j.code, 'entries', n) order by j.code), '[]'::jsonb)
|
|
238
|
+
into v_journals
|
|
239
|
+
from (select e ->> 'journal_code' as code, count(*) as n
|
|
240
|
+
from jsonb_array_elements(coalesce(p_books -> 'entries', '[]'::jsonb)) e
|
|
241
|
+
group by 1) per
|
|
242
|
+
join journals j on j.company_id = p_company_id and j.code = per.code;
|
|
243
|
+
|
|
244
|
+
insert into book_imports (company_id, source, checksum, file_names, entry_count, line_count,
|
|
245
|
+
first_number, last_number, opening_number)
|
|
246
|
+
values (p_company_id, v_source, v_checksum,
|
|
247
|
+
coalesce((select array_agg(value) from jsonb_array_elements_text(coalesce(p_books -> 'file_names', '[]'::jsonb))), '{}'),
|
|
248
|
+
v_entries, v_lines, v_first, v_last, v_opening_no);
|
|
249
|
+
|
|
250
|
+
v_result := jsonb_build_object(
|
|
251
|
+
'dry_run', p_dry_run,
|
|
252
|
+
'source', v_source,
|
|
253
|
+
'entries', v_entries,
|
|
254
|
+
'lines', v_lines,
|
|
255
|
+
'total_debit', v_debit::text,
|
|
256
|
+
'total_credit', v_credit::text,
|
|
257
|
+
'first_number', v_first,
|
|
258
|
+
'last_number', v_last,
|
|
259
|
+
'opening_number', v_opening_no,
|
|
260
|
+
'journals', v_journals,
|
|
261
|
+
'contacts_created', v_created,
|
|
262
|
+
'contacts_found', v_found,
|
|
263
|
+
'fiscal_years_opened', v_years
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
if p_dry_run then
|
|
267
|
+
-- The way out of the block that undoes everything done inside it. A
|
|
268
|
+
-- variable is not part of the transaction, so the answer survives.
|
|
269
|
+
raise exception using errcode = 'EKW01', message = 'rehearsal';
|
|
270
|
+
end if;
|
|
271
|
+
exception
|
|
272
|
+
when sqlstate 'EKW01' then
|
|
273
|
+
null;
|
|
274
|
+
end;
|
|
275
|
+
|
|
276
|
+
return v_result;
|
|
277
|
+
end;
|
|
278
|
+
$$;
|
|
279
|
+
|
|
280
|
+
comment on function import_books(uuid, jsonb, boolean, boolean, boolean) is
|
|
281
|
+
'Takes over books read from another system, whole or not at all: the fiscal years they need (p_open_years), their parties, every entry posted through post_entry() and a trial balance through opening_balance(). Account codes arrive already translated into the company''s chart. p_dry_run does all of it and rolls it back, so the answer and the refusals are the real ones. The same files twice are refused (import_already_done).';
|
|
282
|
+
|
|
283
|
+
revoke execute on function import_books(uuid, jsonb, boolean, boolean, boolean) from public, anon;
|
|
284
|
+
grant execute on function import_books(uuid, jsonb, boolean, boolean, boolean) to authenticated, service_role;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- Ekwo OS — the schema this release defines is 0.7.0.
|
|
2
|
+
--
|
|
3
|
+
-- `ekwo_schema_version()` is the one place the number lives, and a migration
|
|
4
|
+
-- is the only thing that moves it. A database then answers for the files it
|
|
5
|
+
-- has actually run rather than for what somebody believed it had run: the
|
|
6
|
+
-- column default and `init_instance()` both call this function, so a fresh
|
|
7
|
+
-- install records the new number without a second edit, and `ekwo migrate`
|
|
8
|
+
-- reads it back onto `instance.schema_version` for a database that was
|
|
9
|
+
-- installed at an older one.
|
|
10
|
+
--
|
|
11
|
+
-- Between 0.6.0 and here the schema gained two things. `instance.country` is
|
|
12
|
+
-- nullable, because `ekwo init --no-company` installs without a company and
|
|
13
|
+
-- so without a country to write down; `ekwo company new` then creates each
|
|
14
|
+
-- company in its own country through `create_company()`. And `import_books()`
|
|
15
|
+
-- says, when it refuses files it has already imported, which files, read as
|
|
16
|
+
-- which source, when, and what that import wrote. A 0.6.0 database has
|
|
17
|
+
-- neither. The packages of this release call no function a 0.6.0 database
|
|
18
|
+
-- lacks, but they are built and tested against the installation these two
|
|
19
|
+
-- migrations leave, and `ekwo migrate` brings a 0.6.0 one there in a second:
|
|
20
|
+
-- so the packages declare 0.7.0 as their floor and refuse an older database by
|
|
21
|
+
-- name, as every release has, rather than answering for one they were never
|
|
22
|
+
-- run against.
|
|
23
|
+
|
|
24
|
+
create or replace function ekwo_schema_version()
|
|
25
|
+
returns text
|
|
26
|
+
language sql
|
|
27
|
+
immutable
|
|
28
|
+
as $$
|
|
29
|
+
select '0.7.0'::text;
|
|
30
|
+
$$;
|
|
31
|
+
|
|
32
|
+
comment on function ekwo_schema_version() is
|
|
33
|
+
'Schema version of the installed release. Bumped by a migration, never by hand.';
|
|
34
|
+
|
|
35
|
+
-- `create or replace` keeps the privileges the function already had, and the
|
|
36
|
+
-- revoke is what every migration of this directory ends with: a function that
|
|
37
|
+
-- comes out with the built-in default is published by Supabase as an
|
|
38
|
+
-- anonymous RPC endpoint.
|
|
39
|
+
revoke execute on all functions in schema public from public;
|
|
40
|
+
grant execute on function ekwo_schema_version() to authenticated, service_role;
|
package/dist/auth.d.ts
CHANGED
|
@@ -38,6 +38,23 @@ export interface CreateAuthUserOptions {
|
|
|
38
38
|
}
|
|
39
39
|
/** How the bootstrap gets a user id. Injected, so tests never hit the network. */
|
|
40
40
|
export type CreateAuthUser = (options: CreateAuthUserOptions) => Promise<AuthUser>;
|
|
41
|
+
/**
|
|
42
|
+
* The headers the admin API is called with, for either form of the key.
|
|
43
|
+
*
|
|
44
|
+
* A legacy `service_role` key is a JWT, and GoTrue has always read it from
|
|
45
|
+
* `Authorization: Bearer` as well as from `apikey`. A secret key of the newer
|
|
46
|
+
* form — `sb_secret_…` — is a short string and not a JWT: Supabase documents
|
|
47
|
+
* that it travels on `apikey` and not on `Authorization: Bearer`, where
|
|
48
|
+
* anything that tries to verify it as a JWT refuses it. The CLI used to send
|
|
49
|
+
* it both ways; a walkthrough on a new project stopped at the first
|
|
50
|
+
* administrator with such a key, although a probe of 22 September 2026 found
|
|
51
|
+
* the gateway still tolerating a Bearer equal to `apikey`. What is documented
|
|
52
|
+
* is what is relied on: the new form goes on `apikey` alone, and the gateway
|
|
53
|
+
* turns it into the role it stands for.
|
|
54
|
+
*/
|
|
55
|
+
export declare function adminHeaders(key: string): Record<string, string>;
|
|
56
|
+
/** A key of the newer form, `sb_secret_…` or `sb_publishable_…`: not a JWT. */
|
|
57
|
+
export declare function isOpaqueKey(key: string): boolean;
|
|
41
58
|
/**
|
|
42
59
|
* Creates the first administrator in the customer's own Supabase Auth.
|
|
43
60
|
*
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEjF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,kFAAkF;AAClF,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEjF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,kFAAkF;AAClF,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,qBAAqB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAMnF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMhE;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEhD;AAiBD;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,EAAE,cAwE5B,CAAC;AAEF,4DAA4D;AAC5D,wBAAsB,mBAAmB,CAAC,EACxC,WAAW,EACX,cAAc,EACd,KAAK,EACL,SAA4B,GAC7B,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAiBhC"}
|