@aventara/client 1.0.0-rc.1 → 1.0.0-rc.10
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/CHANGELOG.md +194 -0
- package/README.md +37 -1
- package/dist/cli/command.parser.d.ts +4 -3
- package/dist/cli/command.parser.js +3 -3
- package/dist/cli/generation-failure.renderer.d.ts +2 -1
- package/dist/cli/generation-success.renderer.d.ts +2 -1
- package/dist/cli/step.reporter.d.ts +2 -1
- package/dist/cli/terminal.prompter.d.ts +2 -1
- package/dist/config/client-config.interface.d.ts +17 -0
- package/dist/config/config.loader.d.ts +8 -3
- package/dist/config/config.loader.js +20 -2
- package/dist/config/config.resolver.d.ts +10 -3
- package/dist/config/config.resolver.js +28 -0
- package/dist/config/env.cascade.d.ts +2 -6
- package/dist/config/env.cascade.js +3 -3
- package/dist/config/module-style.resolver.d.ts +3 -6
- package/dist/config/module-style.resolver.js +2 -2
- package/dist/config/tsconfig.locator.d.ts +2 -1
- package/dist/config/tsconfig.locator.js +14 -2
- package/dist/contract/contract.acceptance.d.ts +0 -1
- package/dist/contract/contract.acceptance.js +1 -1
- package/dist/contract/contract.fetcher.d.ts +2 -1
- package/dist/contract/contract.loader.d.ts +3 -2
- package/dist/emit/access.emitter.d.ts +12 -0
- package/dist/emit/access.emitter.js +263 -0
- package/dist/emit/banner.emitter.d.ts +6 -1
- package/dist/emit/banner.emitter.js +12 -8
- package/dist/emit/client-surface.emitter.js +79 -7
- package/dist/emit/client-tree.emitter.d.ts +9 -2
- package/dist/emit/client-tree.emitter.js +45 -14
- package/dist/emit/derivation.emitter.d.ts +3 -3
- package/dist/emit/derivation.emitter.js +6 -3
- package/dist/emit/emitted-tree.interface.d.ts +1 -1
- package/dist/emit/field-check.emitter.d.ts +2 -1
- package/dist/emit/field-check.emitter.js +2 -13
- package/dist/emit/module-specifier.scanner.d.ts +2 -1
- package/dist/emit/name.deriver.d.ts +2 -3
- package/dist/emit/name.deriver.js +4 -1
- package/dist/emit/named-type.emitter.js +12 -2
- package/dist/emit/runtime.emitter.d.ts +5 -4
- package/dist/emit/runtime.emitter.js +101 -7
- package/dist/emit/scalar.codec.js +223 -6
- package/dist/emit/transaction.emitter.js +7 -3
- package/dist/generate.d.ts +3 -2
- package/dist/generate.js +1 -1
- package/dist/hydration/hydration-tag.format.d.ts +11 -0
- package/dist/hydration/hydration-tag.format.js +6 -0
- package/dist/init/client-init.planner.d.ts +3 -2
- package/dist/init/client-init.questions.d.ts +1 -12
- package/dist/init/client-init.questions.js +2 -2
- package/dist/internal.d.ts +25 -0
- package/dist/internal.js +11 -0
- package/dist/output/output.validator.d.ts +3 -4
- package/dist/output/output.validator.js +2 -2
- package/dist/output/output.writer.d.ts +3 -2
- package/package.json +9 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,199 @@
|
|
|
1
1
|
# @aventara/client
|
|
2
2
|
|
|
3
|
+
## 1.0.0-rc.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7ee547b: A ClientContract whose `access` section states Aventara Access's `kiosk` verbs gives the generated client
|
|
8
|
+
`$access.switchUser`, `lock`, `setPin`, `enrollDevice` and `revokeDevice`, each a `POST` to Access's own route with its
|
|
9
|
+
arguments typed from the section's schema and its answer projected onto the result schema (`lock`, `setPin` and
|
|
10
|
+
`revokeDevice` resolve nothing). A section without them emits no member for them.
|
|
11
|
+
- d7e7369: A ClientContract with the `access` section gives the generated client `$access`: `can(questions)` (one request to
|
|
12
|
+
`/_access/can`), and exactly the Aventara Access verbs the section states (`me` with `GET` and `cache: "no-store"`,
|
|
13
|
+
`signIn`, `signUp`, `signOut`, `resetPassword`), each result projected onto the section's schema. `AvAccessMe` is
|
|
14
|
+
`me`'s result type and `AvAccessError` what a non-2xx Access answer throws. A client without the section is emitted
|
|
15
|
+
byte for byte as before. A ClientContract whose Access URL is on another origin than the
|
|
16
|
+
entrypoint's is refused unless `framework.client.ts` lists that origin in the new `accessOrigins`.
|
|
17
|
+
- 9d423f9: `avclient generate`'s reference step (a solution-style `tsconfig.json`) matches `${configDir}` entries of `files`,
|
|
18
|
+
`include` and `exclude`. `get-tsconfig` 4.10.0 makes them absolute and its file matcher joined them under the config's
|
|
19
|
+
directory again, so a referenced project including the client through `${configDir}` was passed over.
|
|
20
|
+
- 04bb39a: `engines.node` is now `^22.23.4 || >=24.22.1`, the Node security releases of 2026-10-20 (CVE-2026-105481,
|
|
21
|
+
CVE-2026-105482, CVE-2026-105483, CVE-2026-106069, CVE-2026-106072, CVE-2026-106073, CVE-2026-106074,
|
|
22
|
+
CVE-2026-111497). The bins refuse an older Node in one sentence naming that range.
|
|
23
|
+
- 88263a1: A value projected onto an `access` verb's result schema is refused with the projector's own `TypeError` when the schema
|
|
24
|
+
is outside the forms a Client Contract states (a free-form object or list, a tuple read past its length), whatever the
|
|
25
|
+
value, an empty one included. A Client Contract that passed its structure check never holds such a schema.
|
|
26
|
+
- Updated dependencies [587dd01]
|
|
27
|
+
- Updated dependencies [d7e7369]
|
|
28
|
+
- Updated dependencies [7ee547b]
|
|
29
|
+
- Updated dependencies [f52c499]
|
|
30
|
+
- Updated dependencies [2907484]
|
|
31
|
+
- Updated dependencies [a6bbdf0]
|
|
32
|
+
- Updated dependencies [3e26549]
|
|
33
|
+
- Updated dependencies [a6bbdf0]
|
|
34
|
+
- Updated dependencies [6f3f6f6]
|
|
35
|
+
- Updated dependencies [04bb39a]
|
|
36
|
+
- Updated dependencies [3fb3333]
|
|
37
|
+
- Updated dependencies [827ccb6]
|
|
38
|
+
- Updated dependencies [7f5abc3]
|
|
39
|
+
- Updated dependencies [88263a1]
|
|
40
|
+
- Updated dependencies [10341d5]
|
|
41
|
+
- Updated dependencies [8129844]
|
|
42
|
+
- Updated dependencies [88263a1]
|
|
43
|
+
- Updated dependencies [3020b5c]
|
|
44
|
+
- Updated dependencies [88263a1]
|
|
45
|
+
- Updated dependencies [88263a1]
|
|
46
|
+
- @aventara/core@1.0.0-rc.10
|
|
47
|
+
|
|
48
|
+
## 1.0.0-rc.9
|
|
49
|
+
|
|
50
|
+
### Patch Changes
|
|
51
|
+
|
|
52
|
+
- 99278e4: `aventara-build` reads a Next.js project's files from `src/aventara/` and, with `--client`, writes its browser client.
|
|
53
|
+
|
|
54
|
+
- A project whose `package.json` depends on `@aventara/next` keeps its configuration and adapter in
|
|
55
|
+
`src/aventara/config.ts` and `src/aventara/adapter.ts`; the build runs them there, and a configuration that imports no
|
|
56
|
+
Resource tree has its generated files in `src/aventara/generated/`. Every other project keeps
|
|
57
|
+
`src/aventara.config.ts` and `src/aventara.adapter.ts`, unchanged. A missing file is named with where the project's
|
|
58
|
+
host keeps it, and a project depending on both `@aventara/nest` and `@aventara/next` is refused in one sentence.
|
|
59
|
+
- `aventara-build --client` also writes the browser client from the ClientContract it has just compiled, with no
|
|
60
|
+
running server: `src/aventara/client.ts` and the client's modules under `src/aventara/generated/`, the same modules
|
|
61
|
+
`avclient generate` writes for that ClientContract except that the entrypoint is the app's own `api` on the page's
|
|
62
|
+
origin (`/api`) and the regenerate instructions. Its imports are spelled as the project's `tsconfig.json` says, and nothing it writes imports
|
|
63
|
+
`@aventara/client`.
|
|
64
|
+
- `src/aventara/client.ts` exports `avClient` and `avHydrate`, and re-exports every name `avclient generate`'s
|
|
65
|
+
`AvClient.ts` exports besides its default (`AvClient`, the Resource types, the enums, `AvDecimal`, the error
|
|
66
|
+
classes), so `import { AvDecimal } from "@/aventara/client"` works. The generated files and the contract-mismatch
|
|
67
|
+
error say to regenerate with `aventara-build --client` (the project's `aventara:prepare` script). `avClient` calls the API from the browser; a call made
|
|
68
|
+
on the server (a Client Component rendering there) rejects with one sentence pointing to `@/aventara/server` and
|
|
69
|
+
`@/aventara/universal`, and sends nothing. `avHydrate` revives data `avDehydrate` sends from the server: tagged
|
|
70
|
+
dates, `bigint`s, byte arrays and decimals become `Date`, `bigint`, `Uint8Array` and the client's own `AvDecimal`,
|
|
71
|
+
for TanStack Query's `deserializeData` or an SWR `fallback`.
|
|
72
|
+
- `aventara-build --check --client` checks those files too: a missing or stale one, or one an earlier ClientContract's
|
|
73
|
+
client left, exits 1 naming it. `--client` is refused in a NestJS project, whose frontends keep using
|
|
74
|
+
`avclient generate`, which is unchanged.
|
|
75
|
+
- `@aventara/client` gains an `@aventara/client/internal` entry, which `@aventara/build` reads the generator through.
|
|
76
|
+
It is not public API.
|
|
77
|
+
|
|
78
|
+
- Updated dependencies [205a379]
|
|
79
|
+
- Updated dependencies [a0bb05e]
|
|
80
|
+
- Updated dependencies [86ab319]
|
|
81
|
+
- Updated dependencies [fdf52e6]
|
|
82
|
+
- @aventara/core@1.0.0-rc.9
|
|
83
|
+
|
|
84
|
+
## 1.0.0-rc.8
|
|
85
|
+
|
|
86
|
+
1.0.0-rc.5, rc.6 and rc.7 were tagged but never published; 1.0.0-rc.8 contains everything listed under them and the changes below.
|
|
87
|
+
|
|
88
|
+
### Patch Changes
|
|
89
|
+
|
|
90
|
+
- A generated client's results read as their value types in an editor: `body: string | null`, `published: boolean`,
|
|
91
|
+
`publishedAt: Date | null`, where a nullable, enum or `boolean` field was shown as `AvScalarValueType<…>` with the
|
|
92
|
+
client's Contract as its argument, and a result as `ProjectedFields<…>`. Run `avclient generate` again to pick it up.
|
|
93
|
+
What the client accepts and returns is unchanged.
|
|
94
|
+
- Updated dependencies [1c8e4ee]
|
|
95
|
+
- @aventara/core@1.0.0-rc.8
|
|
96
|
+
|
|
97
|
+
## 1.0.0-rc.7
|
|
98
|
+
|
|
99
|
+
1.0.0-rc.5 and 1.0.0-rc.6 were tagged but never published; 1.0.0-rc.7 contains everything listed under them and the changes below.
|
|
100
|
+
|
|
101
|
+
### Patch Changes
|
|
102
|
+
|
|
103
|
+
- Updated dependencies [f917c1c]
|
|
104
|
+
- @aventara/core@1.0.0-rc.7
|
|
105
|
+
|
|
106
|
+
## 1.0.0-rc.6
|
|
107
|
+
|
|
108
|
+
1.0.0-rc.5 was tagged but never published. 1.0.0-rc.6 contains everything listed under 1.0.0-rc.5 and the fix below.
|
|
109
|
+
|
|
110
|
+
### Patch Changes
|
|
111
|
+
|
|
112
|
+
- Updated dependencies [1cf72e0]
|
|
113
|
+
- @aventara/core@1.0.0-rc.6
|
|
114
|
+
|
|
115
|
+
## 1.0.0-rc.5
|
|
116
|
+
|
|
117
|
+
### Patch Changes
|
|
118
|
+
|
|
119
|
+
- Updated dependencies [4795ff1]
|
|
120
|
+
- Updated dependencies [9e178ca]
|
|
121
|
+
- @aventara/core@1.0.0-rc.5
|
|
122
|
+
|
|
123
|
+
## 1.0.0-rc.4
|
|
124
|
+
|
|
125
|
+
### Patch Changes
|
|
126
|
+
|
|
127
|
+
- Updated dependencies [e3d03a7]
|
|
128
|
+
- Updated dependencies [d10639a]
|
|
129
|
+
- Updated dependencies [f67e68c]
|
|
130
|
+
- Updated dependencies [708556c]
|
|
131
|
+
- Updated dependencies [3a0dfca]
|
|
132
|
+
- Updated dependencies [99169d2]
|
|
133
|
+
- Updated dependencies [0fd2608]
|
|
134
|
+
- Updated dependencies [154e440]
|
|
135
|
+
- Updated dependencies [2fcffdb]
|
|
136
|
+
- @aventara/core@1.0.0-rc.4
|
|
137
|
+
|
|
138
|
+
## 1.0.0-rc.3
|
|
139
|
+
|
|
140
|
+
### Patch Changes
|
|
141
|
+
|
|
142
|
+
- Updated dependencies [b38034d]
|
|
143
|
+
- Updated dependencies [b38034d]
|
|
144
|
+
- Updated dependencies [b38034d]
|
|
145
|
+
- Updated dependencies [b38034d]
|
|
146
|
+
- Updated dependencies [b38034d]
|
|
147
|
+
- Updated dependencies [b38034d]
|
|
148
|
+
- @aventara/core@1.0.0-rc.3
|
|
149
|
+
|
|
150
|
+
## 1.0.0-rc.2
|
|
151
|
+
|
|
152
|
+
### Patch Changes
|
|
153
|
+
|
|
154
|
+
- The optional `typescript` peer range is `>=5.7.0` (it was `>=5.5.0`), the lowest TypeScript Aventara's types
|
|
155
|
+
compile under. `avclient generate` type-checks the client with TypeScript 5.7 or later; under an older one it parses
|
|
156
|
+
the output with Node's TypeScript parser (`checked: syntax`) and says so in one warning, as it did below 5.5.
|
|
157
|
+
- A generated client sends an `undefined` array element (or a hole) as `null`, as `JSON.stringify` writes it, and its
|
|
158
|
+
`json` codec leaves out a key holding `undefined` and writes such an element as `null`. A `json` value
|
|
159
|
+
`{ a: undefined, b: [undefined] }` is sent as `{"b":[null]}`, the value the server stores when an in-process caller
|
|
160
|
+
passes it. In rc.1 the client refused the array element with a `TypeError` before sending. Regenerate the client.
|
|
161
|
+
- A generated client's `json` values admit a key holding `undefined` in their type, as core's `AvJsonValue` now does,
|
|
162
|
+
so an object with optional properties can be passed where a `json` value is taken; the key is not sent. In rc.1 it
|
|
163
|
+
was a compile error. Regenerate the client.
|
|
164
|
+
- A generated client refuses at compile time a filter `mode` or `path` that qualifies no operator: one alone, or one
|
|
165
|
+
whose only neighbour is a `not` holding operators (`{ mode: "insensitive", not: { contains: "x" } }`). Write it
|
|
166
|
+
inside the `not`. The server refuses the same filters (`A2004`, `V1001`). Regenerate the client.
|
|
167
|
+
- A generated client types a filter's `mode` by the field: `"default"` always, and `"sensitive"` or `"insensitive"`
|
|
168
|
+
only where the ClientContract's `filterModes` lists them; any other mode is a compile error. On a `json` field an
|
|
169
|
+
operator object that names `path` takes the modes `pathFilterModes` lists instead, so on Postgres
|
|
170
|
+
`where: { meta: { stringContains: "x", mode: "insensitive" } }` is a compile error and
|
|
171
|
+
`where: { meta: { path: ["label"], stringContains: "x", mode: "insensitive" } }` compiles. `isEmpty` is typed as a boolean, `path` as an array of strings and a `json` field's `string*`
|
|
172
|
+
operand as a string. The server refuses the same values (`A2004`), so the client adds no runtime check of its own.
|
|
173
|
+
Regenerate the client: the Contract hash changes.
|
|
174
|
+
- The generated client refuses an `undefined` value in a filter before anything is sent. JSON drops `undefined`, so
|
|
175
|
+
`avClient.Post.update.many({ where: { id: undefined }, data })` reached the server as `where: {}` and updated every
|
|
176
|
+
row; the same went for `find`, `count`, `delete` and a transaction step. Now an `undefined` anywhere inside a
|
|
177
|
+
`where` (`AND`, `OR`, `NOT`, relation filters, operator objects such as `{ equals: undefined }` or
|
|
178
|
+
`{ isEmpty: undefined }`, `in` lists), a `cursor`, a unique selector, the `where` or `cursor` of a relation in
|
|
179
|
+
`select` or `include`, or a nested write's selectors (`$connect`, `$disconnect`, `$set`, `$delete`, the `where` of
|
|
180
|
+
`$update`, `$upsert` and `$connectOrCreate`) throws `AvValidationError` (`A2004`) with a `V1001` issue at the path
|
|
181
|
+
the server uses (`["arguments", "where", "id"]`, or `["operations", 0, "args", "where", "id"]` with the step's
|
|
182
|
+
`operation` for a transaction), and no request is made. A `where`, `cursor`, `limit` or `offset` that is itself
|
|
183
|
+
`undefined` is refused the same way, with the server's code (`V1001`; `V1007` for a unique selector, `V1009` for a
|
|
184
|
+
cursor), at the top level, in a relation under `select` or `include`, and in a nested write's `where`. Leave the
|
|
185
|
+
key out to mean no filter. Write data is unchanged: an `undefined` field there is not sent. Regenerate the client
|
|
186
|
+
to get the check.
|
|
187
|
+
- `avclient generate` in a directory with no config names the extensions it looks for as the docs list them:
|
|
188
|
+
`no framework.client.ts, .mts, .cts, .js, .mjs or .cjs in <directory>; …`. In rc.1 it read
|
|
189
|
+
`no framework.client.{js,ts,mjs,cjs,mts,cts} in <directory>`. `avclient --help` and `avclient generate --help` list
|
|
190
|
+
them in the same order: `framework.client.ts (or .mts, .cts, .js, .mjs, .cjs)`. Which files are read is unchanged.
|
|
191
|
+
- Updated dependencies [9366e16]
|
|
192
|
+
- Updated dependencies [9366e16]
|
|
193
|
+
- Updated dependencies [9366e16]
|
|
194
|
+
- Updated dependencies [9366e16]
|
|
195
|
+
- @aventara/core@1.0.0-rc.2
|
|
196
|
+
|
|
3
197
|
## 1.0.0-rc.1
|
|
4
198
|
|
|
5
199
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -96,7 +96,7 @@ A failed run leaves the previous output exactly as it was. The whole tree is wri
|
|
|
96
96
|
`generateAt`, validated there as one program, and only then moved into place. A run killed part-way is repaired by the
|
|
97
97
|
next run that writes, before it writes anything. A first run that fails removes the directories it created.
|
|
98
98
|
|
|
99
|
-
The validate step is a real type check when your project has the optional peer `typescript` (5.
|
|
99
|
+
The validate step is a real type check when your project has the optional peer `typescript` (5.7 to 6). It is resolved
|
|
100
100
|
from your project, so `npx @aventara/client@rc init` type-checks too, under a consumer's strictest plausible settings
|
|
101
101
|
and with nothing outside the tree resolvable. Without it, or under TypeScript 7 (which has no classic compiler API to
|
|
102
102
|
check with), the check falls back to a parse with Node's own TypeScript parser and says so in one warning. It is never
|
|
@@ -192,6 +192,42 @@ The platform `fetch` is read when a call is made, not when the client is importe
|
|
|
192
192
|
where there is no `fetch`; a call does, saying why. An entrypoint carrying credentials is refused when the config is
|
|
193
193
|
resolved.
|
|
194
194
|
|
|
195
|
+
## Aventara Access: `$access`
|
|
196
|
+
|
|
197
|
+
When the deployment's ClientContract has the `access` section (the framework is configured with `access`), the client
|
|
198
|
+
has `$access`:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
const answers = await avClient.$access.can([
|
|
202
|
+
{ resource: "Order", action: "update", where: { id: 41 } },
|
|
203
|
+
{ resource: "Refund", action: "create" },
|
|
204
|
+
]); // [boolean, boolean], one request to /_access/can
|
|
205
|
+
await avClient.$access.signIn({ email, password }); // Access's own route
|
|
206
|
+
const me = await avClient.$access.me(); // AvAccessMe | null
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`can` is always there; `me`, `signIn`, `signUp`, `signOut` and `resetPassword`, and on Access's `kiosk` profile
|
|
210
|
+
`switchUser`, `lock`, `setPin`, `enrollDevice` and `revokeDevice`, exactly when the section states them.
|
|
211
|
+
Each verb calls Access's own route (`me` with `GET` and `cache: "no-store"`), and resolves its result projected onto the
|
|
212
|
+
section's schema: members the schema does not declare are dropped. `AvAccessMe` is `me`'s result type. A non-2xx answer
|
|
213
|
+
from Access throws `AvAccessError` (`status`, `code`, `message`); `can`'s refusals are `AvError`s, as every call's.
|
|
214
|
+
Without the section there is no `$access`.
|
|
215
|
+
|
|
216
|
+
Where Access lives decides where a sign-in's credentials go, so the generator emits an absolute Access URL only when it
|
|
217
|
+
is on the entrypoint's origin, or on an origin `framework.client.ts` lists:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
export default defineClientConfig({
|
|
221
|
+
entrypoint: env("AVENTARA_API_URL"),
|
|
222
|
+
generateAt: "./src/api",
|
|
223
|
+
accessOrigins: ["https://auth.example.com"],
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
A verb on another origin carries cookies only when your `fetch` sends them: pass one that does
|
|
228
|
+
(`new AvClient({ fetch: (url, init) => fetch(url, { ...init, credentials: "include" }) })`), and have Access allow
|
|
229
|
+
that origin with credentials (CORS).
|
|
230
|
+
|
|
195
231
|
## Up to date
|
|
196
232
|
|
|
197
233
|
A rerun asks the deployment conditionally (`If-None-Match`, the ClientContract hash of the output it finds), but only
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare const USAGE = "avclient \u2014 generate a typed Aventara client from a deployed ClientContract.\n\nUsage:\n avclient generate [--yes] Read framework.client.ts (or .
|
|
2
|
-
export declare const GENERATE_USAGE = "Usage: avclient generate [--yes]\n\nRead framework.client.ts (or .
|
|
1
|
+
export declare const USAGE = "avclient \u2014 generate a typed Aventara client from a deployed ClientContract.\n\nUsage:\n avclient generate [--yes] Read framework.client.ts (or .mts, .cts, .js, .mjs,\n .cjs) in the current directory, fetch\n <entrypoint>/_contract, and write AvClient.ts and\n generated/ into its generateAt directory, its imports\n spelled as the project's tsconfig.json says.\n avclient init [options] Set up this frontend: write framework.client.ts, the\n .env entry, the avclient:generate script and the\n @aventara/client devDependency; install; generate.\n --entrypoint <url> The server's entrypoint [http://localhost:3000/api].\n --env-var <NAME> Read it from this variable [AVENTARA_API_URL].\n --no-env-var Write it into framework.client.ts as a literal.\n --generate-at <dir> Where the client goes [./src/api].\n --package-manager <npm|pnpm> [the lockfile's, else the launching one, else npm]\n --skip-install Print the install instead of running it.\n --skip-generate Do not generate now.\n -y, --yes Accept every default, and replace differing content.\n avclient --help Print this and exit 0.\n avclient <command> --help Print that command's usage and exit 0.\n avclient --version, -v Print this generator's version and exit 0.\n\nOptions:\n -y, --yes Overwrite or remove content in AvClient.ts and generated/ that the\n generator did not produce, without asking. Without it, such content\n is listed and you are asked; where nobody can answer (stdin is not a\n terminal, as in CI), the run is refused and nothing is touched.\n\nThe generator owns AvClient.ts and generated/ in generateAt, and nothing else\nthere: your own files beside them are never read, moved or removed. Generated\nfiles are replaced on every run; do not edit them.\n\nBefore framework.client.ts is evaluated, the .env cascade is read from the\ncurrent directory, highest precedence first: the process environment,\n.env.<mode>.local, .env.<mode>, .env.local, .env \u2014 where mode is NODE_ENV, or\n\"development\".\n";
|
|
2
|
+
export declare const GENERATE_USAGE = "Usage: avclient generate [--yes]\n\nRead framework.client.ts (or .mts, .cts, .js, .mjs, .cjs) in the current directory,\nfetch <entrypoint>/_contract, and write AvClient.ts and generated/ into its\ngenerateAt directory, its imports spelled as the project's tsconfig.json says.\n\nOptions:\n -y, --yes Overwrite or remove content in AvClient.ts and generated/ that the\n generator did not produce, without asking. Without it, such content\n is listed and you are asked; where nobody can answer (stdin is not a\n terminal, as in CI), the run is refused and nothing is touched.\n\nThe generator owns AvClient.ts and generated/ in generateAt, and nothing else\nthere: your own files beside them are never read, moved or removed.\n\nBefore the config is evaluated, the .env cascade is read from the current\ndirectory, highest precedence first: the process environment, .env.<mode>.local,\n.env.<mode>, .env.local, .env \u2014 where mode is NODE_ENV, or \"development\".\n";
|
|
3
3
|
export declare const INIT_USAGE = "Usage: avclient init [options]\n\nSet up this frontend: write framework.client.ts, the .env entry, the avclient:generate\nscript and the @aventara/client devDependency; install; generate.\n\nOptions:\n --entrypoint <url> The server's entrypoint [http://localhost:3000/api].\n --env-var <NAME> Read it from this variable [AVENTARA_API_URL].\n --no-env-var Write it into framework.client.ts as a literal.\n --generate-at <dir> Where the client goes [./src/api].\n --package-manager <npm|pnpm> [the lockfile's, else the launching one, else npm]\n --skip-install Print the install instead of running it.\n --skip-generate Do not generate now.\n --verbose Show the install's output as it runs.\n -y, --yes Accept every default, and replace differing content.\n\nOn a terminal every unanswered question is asked; anywhere else, pass its flag\nor --yes, or the run stops before writing anything.\n";
|
|
4
4
|
export type ClientInitCommand = {
|
|
5
5
|
readonly command: "init";
|
|
@@ -12,7 +12,7 @@ export type ClientInitCommand = {
|
|
|
12
12
|
readonly verbose?: boolean;
|
|
13
13
|
};
|
|
14
14
|
/** What the command line asked for. */
|
|
15
|
-
|
|
15
|
+
type CliCommand = {
|
|
16
16
|
readonly command: "help";
|
|
17
17
|
readonly topic?: "generate" | "init";
|
|
18
18
|
} | {
|
|
@@ -30,3 +30,4 @@ export declare class AvCliCommandError extends Error {
|
|
|
30
30
|
* `--help`/`-h` or `--version`/`-v`.
|
|
31
31
|
*/
|
|
32
32
|
export declare function parseCliCommand(argv: readonly string[]): CliCommand;
|
|
33
|
+
export {};
|
|
@@ -2,8 +2,8 @@ import { CLIENT_CONFIG_FILE } from "../config/config.loader.js";
|
|
|
2
2
|
export const USAGE = `avclient — generate a typed Aventara client from a deployed ClientContract.
|
|
3
3
|
|
|
4
4
|
Usage:
|
|
5
|
-
avclient generate [--yes] Read ${CLIENT_CONFIG_FILE} (or .
|
|
6
|
-
.
|
|
5
|
+
avclient generate [--yes] Read ${CLIENT_CONFIG_FILE} (or .mts, .cts, .js, .mjs,
|
|
6
|
+
.cjs) in the current directory, fetch
|
|
7
7
|
<entrypoint>/_contract, and write AvClient.ts and
|
|
8
8
|
generated/ into its generateAt directory, its imports
|
|
9
9
|
spelled as the project's tsconfig.json says.
|
|
@@ -39,7 +39,7 @@ current directory, highest precedence first: the process environment,
|
|
|
39
39
|
`;
|
|
40
40
|
export const GENERATE_USAGE = `Usage: avclient generate [--yes]
|
|
41
41
|
|
|
42
|
-
Read ${CLIENT_CONFIG_FILE} (or .
|
|
42
|
+
Read ${CLIENT_CONFIG_FILE} (or .mts, .cts, .js, .mjs, .cjs) in the current directory,
|
|
43
43
|
fetch <entrypoint>/_contract, and write AvClient.ts and generated/ into its
|
|
44
44
|
generateAt directory, its imports spelled as the project's tsconfig.json says.
|
|
45
45
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
interface GenerationFailureReport {
|
|
2
2
|
readonly exitCode: number;
|
|
3
3
|
/** What goes to stderr, newline-terminated: the warnings carried, then the sentence. */
|
|
4
4
|
readonly text: string;
|
|
5
5
|
}
|
|
6
6
|
export declare function renderGenerationFailure(error: unknown): GenerationFailureReport;
|
|
7
|
+
export {};
|
|
@@ -6,7 +6,7 @@ import type { ClientGenerated, ClientUpToDate, ForeignOutputContent } from "../g
|
|
|
6
6
|
* them — renames, the degraded check, crash recovery — so the same run prints the
|
|
7
7
|
* same lines.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
interface GenerationSuccessReport {
|
|
10
10
|
/** What goes to stdout, newline-terminated. */
|
|
11
11
|
readonly stdout: string;
|
|
12
12
|
/** What goes to stderr: one line per warning, or nothing. */
|
|
@@ -29,3 +29,4 @@ export declare const FOREIGN_CONTENT_QUESTION = "avclient: overwrite them and ge
|
|
|
29
29
|
* are reported as a refused one's are.
|
|
30
30
|
*/
|
|
31
31
|
export declare function renderForeignContentCancellation(found: ForeignOutputContent, asked: boolean): string;
|
|
32
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type ProgressMode = "live" | "plain" | "off";
|
|
2
2
|
/** `live` only on a terminal that is not CI and accepts control sequences. */
|
|
3
3
|
export declare function progressModeOf(isTTY: boolean | undefined, env: Readonly<Record<string, string | undefined>>): Exclude<ProgressMode, "off">;
|
|
4
|
-
|
|
4
|
+
type StepReporterOptions = {
|
|
5
5
|
/** Where the lines go: the tool's stderr, so its stdout stays its result. */
|
|
6
6
|
readonly write: (text: string) => void;
|
|
7
7
|
readonly mode: ProgressMode;
|
|
@@ -29,3 +29,4 @@ export type StepReporter = {
|
|
|
29
29
|
/** `12.4s`, or `1m 02s` from a minute. */
|
|
30
30
|
export declare function formatElapsed(milliseconds: number): string;
|
|
31
31
|
export declare function createStepReporter(options: StepReporterOptions): StepReporter;
|
|
32
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
type TerminalPrompter = {
|
|
2
2
|
readonly ask: (prompt: string) => Promise<string>;
|
|
3
3
|
readonly confirm: (question: string) => Promise<boolean>;
|
|
4
4
|
readonly close: () => void;
|
|
5
5
|
};
|
|
6
6
|
export declare function createTerminalPrompter(): TerminalPrompter;
|
|
7
|
+
export {};
|
|
@@ -28,6 +28,13 @@ export interface AvClientConfigInput {
|
|
|
28
28
|
* `generateAt` is used.
|
|
29
29
|
*/
|
|
30
30
|
readonly tsconfigFile?: string;
|
|
31
|
+
/**
|
|
32
|
+
* The origins other than the entrypoint's that `$access` may send a
|
|
33
|
+
* sign-in to (`"https://auth.example.com"`): where the deployment mounted
|
|
34
|
+
* Aventara Access, when that is another origin. Absent, the generator
|
|
35
|
+
* refuses a ClientContract whose Access URL is on another origin.
|
|
36
|
+
*/
|
|
37
|
+
readonly accessOrigins?: readonly AvClientConfigValue[];
|
|
31
38
|
}
|
|
32
39
|
/** A filesystem path known to be absolute. */
|
|
33
40
|
export type AbsolutePath = string & {
|
|
@@ -44,11 +51,21 @@ export interface ClientEntrypoint {
|
|
|
44
51
|
readonly deployment: URL;
|
|
45
52
|
readonly path: EntrypointPath;
|
|
46
53
|
}
|
|
54
|
+
/** An entrypoint on the page's own origin: its mount path alone, such as `/api`. */
|
|
55
|
+
export interface SameOriginEntrypoint {
|
|
56
|
+
/** Absent: the deployment is whichever origin served the page. */
|
|
57
|
+
readonly deployment?: undefined;
|
|
58
|
+
readonly path: EntrypointPath;
|
|
59
|
+
}
|
|
60
|
+
/** The entrypoint a generated client embeds as its default: a deployment's, or the page's own origin. */
|
|
61
|
+
export type EmittedEntrypoint = ClientEntrypoint | SameOriginEntrypoint;
|
|
47
62
|
export interface ResolvedClientConfig {
|
|
48
63
|
readonly entrypoint: ClientEntrypoint;
|
|
49
64
|
/** `generateAt`, made absolute. */
|
|
50
65
|
readonly generateAt: AbsolutePath;
|
|
51
66
|
/** `tsconfigFile`, made absolute; absent when the config names none. */
|
|
52
67
|
readonly tsconfigFile?: AbsolutePath;
|
|
68
|
+
/** `accessOrigins`, each an http(s) origin (`scheme://host[:port]`); empty when the config names none. */
|
|
69
|
+
readonly accessOrigins: readonly string[];
|
|
53
70
|
readonly mode: string;
|
|
54
71
|
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { AvClientConfigInput } from "./client-config.interface.js";
|
|
2
2
|
/** Prisma's `SUPPORTED_EXTENSIONS`, in its order. */
|
|
3
3
|
export declare const CLIENT_CONFIG_FILE_EXTENSIONS: readonly [".js", ".ts", ".mjs", ".cjs", ".mts", ".cts"];
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The same extensions as the docs and `avclient --help` list them, TypeScript
|
|
6
|
+
* first: the order a sentence to the developer names them in. Lookup keeps
|
|
7
|
+
* {@link CLIENT_CONFIG_FILE_EXTENSIONS}' order, Prisma's.
|
|
8
|
+
*/
|
|
9
|
+
export declare const CLIENT_CONFIG_FILE_EXTENSIONS_AS_LISTED: readonly [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
|
|
6
10
|
/** The config file `avclient init` writes when the project has none. */
|
|
7
11
|
export declare const CLIENT_CONFIG_FILE = "framework.client.ts";
|
|
8
|
-
|
|
12
|
+
interface LoadedClientConfig {
|
|
9
13
|
/** The config file's absolute path; `generateAt` resolves against its directory. */
|
|
10
14
|
readonly file: string;
|
|
11
15
|
readonly config: AvClientConfigInput;
|
|
@@ -30,3 +34,4 @@ export declare function findClientConfigFile(directory: string): string | undefi
|
|
|
30
34
|
* or the file does not evaluate, or does not default-export a client config.
|
|
31
35
|
*/
|
|
32
36
|
export declare function loadClientConfigFile(directory: string): Promise<LoadedClientConfig>;
|
|
37
|
+
export {};
|
|
@@ -9,7 +9,15 @@ export const CLIENT_CONFIG_FILE_EXTENSIONS = [
|
|
|
9
9
|
".mts",
|
|
10
10
|
".cts",
|
|
11
11
|
];
|
|
12
|
-
export const
|
|
12
|
+
export const CLIENT_CONFIG_FILE_EXTENSIONS_AS_LISTED = [
|
|
13
|
+
".ts",
|
|
14
|
+
".mts",
|
|
15
|
+
".cts",
|
|
16
|
+
".js",
|
|
17
|
+
".mjs",
|
|
18
|
+
".cjs",
|
|
19
|
+
];
|
|
20
|
+
const CLIENT_CONFIG_BASENAME = "framework.client";
|
|
13
21
|
export const CLIENT_CONFIG_FILE = `${CLIENT_CONFIG_BASENAME}.ts`;
|
|
14
22
|
export function clientConfigFilesIn(directory) {
|
|
15
23
|
return CLIENT_CONFIG_FILE_EXTENSIONS.map((extension) => `${CLIENT_CONFIG_BASENAME}${extension}`).filter((name) => statSync(path.resolve(directory, name), {
|
|
@@ -27,7 +35,8 @@ export function findClientConfigFile(directory) {
|
|
|
27
35
|
export async function loadClientConfigFile(directory) {
|
|
28
36
|
const name = findClientConfigFile(directory);
|
|
29
37
|
if (name === undefined) {
|
|
30
|
-
|
|
38
|
+
const [first, ...others] = CLIENT_CONFIG_FILE_EXTENSIONS_AS_LISTED;
|
|
39
|
+
throw new AvClientConfigError(`no ${CLIENT_CONFIG_BASENAME}${first}, ${others.slice(0, -1).join(", ")} or ${others.at(-1)} in ${path.resolve(directory)}; create ${CLIENT_CONFIG_FILE} with ` +
|
|
31
40
|
"`export default defineClientConfig({ entrypoint, generateAt })` (or run `avclient init`) and run the generator from its directory.");
|
|
32
41
|
}
|
|
33
42
|
const file = path.resolve(directory, name);
|
|
@@ -66,10 +75,19 @@ function clientConfigOf(file, config) {
|
|
|
66
75
|
if (tsconfigFile !== undefined && typeof tsconfigFile !== "string") {
|
|
67
76
|
throw new AvClientConfigError(`${file}'s tsconfigFile must be a string, a path relative to ${path.dirname(file)}.`);
|
|
68
77
|
}
|
|
78
|
+
const accessOrigins = members.accessOrigins;
|
|
79
|
+
if (accessOrigins !== undefined && !Array.isArray(accessOrigins)) {
|
|
80
|
+
throw new AvClientConfigError(`${file}'s accessOrigins must be a list of origins ("https://auth.example.com"), each a string or env("NAME").`);
|
|
81
|
+
}
|
|
69
82
|
return {
|
|
70
83
|
entrypoint: configValueOf(file, "entrypoint", members.entrypoint),
|
|
71
84
|
generateAt: configValueOf(file, "generateAt", members.generateAt),
|
|
72
85
|
...(tsconfigFile === undefined ? {} : { tsconfigFile }),
|
|
86
|
+
...(accessOrigins === undefined
|
|
87
|
+
? {}
|
|
88
|
+
: {
|
|
89
|
+
accessOrigins: accessOrigins.map((origin) => configValueOf(file, "accessOrigins", origin)),
|
|
90
|
+
}),
|
|
73
91
|
};
|
|
74
92
|
}
|
|
75
93
|
function configValueOf(file, member, value) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AvClientConfigInput, AvEnvReference, ClientEntrypoint, ResolvedClientConfig } from "./client-config.interface.js";
|
|
1
|
+
import type { AvClientConfigInput, AvEnvReference, ClientEntrypoint, EmittedEntrypoint, ResolvedClientConfig, SameOriginEntrypoint } from "./client-config.interface.js";
|
|
2
2
|
import type { EnvCascadeResolution } from "./env.cascade.js";
|
|
3
3
|
/** Gives a `framework.client.ts` its type: returns `config` unchanged. */
|
|
4
4
|
export declare function defineClientConfig(config: AvClientConfigInput): AvClientConfigInput;
|
|
@@ -11,7 +11,7 @@ export declare function env(name: string): AvEnvReference;
|
|
|
11
11
|
export declare class AvClientConfigError extends Error {
|
|
12
12
|
readonly name = "AvClientConfigError";
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
interface ClientConfigResolutionInput {
|
|
15
15
|
readonly config: AvClientConfigInput;
|
|
16
16
|
readonly cascade: EnvCascadeResolution;
|
|
17
17
|
/** The directory holding the config file; `generateAt` resolves against it. */
|
|
@@ -26,4 +26,11 @@ export declare function resolveClientConfig(input: ClientConfigResolutionInput):
|
|
|
26
26
|
* @throws AvClientConfigError in one sentence that does not echo the value.
|
|
27
27
|
*/
|
|
28
28
|
export declare function resolveEntrypoint(value: string): ClientEntrypoint;
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* The same-origin entrypoint of a framework mounted at `api`.
|
|
31
|
+
*
|
|
32
|
+
* @throws AvClientConfigError when `api` is not a mount path.
|
|
33
|
+
*/
|
|
34
|
+
export declare function sameOriginEntrypoint(api: string): SameOriginEntrypoint;
|
|
35
|
+
export declare function entrypointHref(entrypoint: EmittedEntrypoint): string;
|
|
36
|
+
export {};
|
|
@@ -24,9 +24,27 @@ export function resolveClientConfig(input) {
|
|
|
24
24
|
: {
|
|
25
25
|
tsconfigFile: path.resolve(input.configDirectory, tsconfigFile),
|
|
26
26
|
}),
|
|
27
|
+
accessOrigins: (input.config.accessOrigins ?? []).map((origin) => resolveAccessOrigin(resolveValue("accessOrigins", origin, input.cascade))),
|
|
27
28
|
mode: input.cascade.mode,
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
function resolveAccessOrigin(value) {
|
|
32
|
+
let url;
|
|
33
|
+
try {
|
|
34
|
+
url = new URL(value);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
url = undefined;
|
|
38
|
+
}
|
|
39
|
+
if (url === undefined ||
|
|
40
|
+
(url.protocol !== "http:" && url.protocol !== "https:") ||
|
|
41
|
+
url.username !== "" ||
|
|
42
|
+
url.password !== "" ||
|
|
43
|
+
url.origin !== value.replace(/\/$/u, "").toLowerCase()) {
|
|
44
|
+
throw new AvClientConfigError('accessOrigins holds a value that is no http(s) origin; each must be scheme, host and port alone ("https://auth.example.com").');
|
|
45
|
+
}
|
|
46
|
+
return url.origin;
|
|
47
|
+
}
|
|
30
48
|
function resolveValue(field, value, cascade) {
|
|
31
49
|
if (typeof value === "string") {
|
|
32
50
|
if (value === "")
|
|
@@ -77,7 +95,17 @@ export function resolveEntrypoint(value) {
|
|
|
77
95
|
function writtenMountPath(value) {
|
|
78
96
|
return value.replace(/^[A-Za-z][A-Za-z0-9+.-]*:[/\\]*[^/\\?#]*/u, "");
|
|
79
97
|
}
|
|
98
|
+
export function sameOriginEntrypoint(api) {
|
|
99
|
+
const normalized = AvProtocol.normalizeEntrypoint(api);
|
|
100
|
+
if (!normalized.ok) {
|
|
101
|
+
throw new AvClientConfigError(`api ${normalized.message}.`);
|
|
102
|
+
}
|
|
103
|
+
return { path: normalized.path };
|
|
104
|
+
}
|
|
80
105
|
export function entrypointHref(entrypoint) {
|
|
106
|
+
if (entrypoint.deployment === undefined) {
|
|
107
|
+
return entrypoint.path;
|
|
108
|
+
}
|
|
81
109
|
const url = new URL(entrypoint.deployment.href);
|
|
82
110
|
url.pathname = entrypoint.path === "" ? "/" : entrypoint.path;
|
|
83
111
|
return url.href.replace(/\/$/, "");
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
export type EnvRecord = Readonly<Record<string, string>>;
|
|
3
3
|
/** The process environment as Node types it: values may be `undefined`. */
|
|
4
4
|
export type ProcessEnvInput = Readonly<Record<string, string | undefined>>;
|
|
5
|
-
/** The mode used when neither an explicit mode nor `NODE_ENV` supplies one. */
|
|
6
|
-
export declare const DEFAULT_ENV_MODE = "development";
|
|
7
5
|
export type EnvFileReader = (filePath: string) => string | undefined;
|
|
8
|
-
|
|
6
|
+
interface EnvCascadeInput {
|
|
9
7
|
/** The directory the five candidates are looked up in. */
|
|
10
8
|
readonly directory: string;
|
|
11
9
|
/** A snapshot of the process environment. Never mutated. */
|
|
@@ -31,10 +29,7 @@ export declare class AvEnvFileError extends Error {
|
|
|
31
29
|
}
|
|
32
30
|
/** The four file candidates for a mode, highest precedence first. */
|
|
33
31
|
export declare function envCascadeCandidates(mode: string): readonly string[];
|
|
34
|
-
export declare function resolveEnvMode(processEnv: ProcessEnvInput, explicit?: string): string;
|
|
35
32
|
export declare function resolveEnvCascade(input: EnvCascadeInput): EnvCascadeResolution;
|
|
36
|
-
/** Reads a candidate from disk; `ENOENT` alone means "not there". */
|
|
37
|
-
export declare function readEnvFileFromDisk(filePath: string): string | undefined;
|
|
38
33
|
/**
|
|
39
34
|
* Parses one file's content. A file whose content holds a line the parser would
|
|
40
35
|
* silently discard is malformed: the user wrote something they expect to take
|
|
@@ -50,3 +45,4 @@ export declare function parseEnvFile(filePath: string, content: string): Record<
|
|
|
50
45
|
* spanning lines — or, when there is none, to the end of its own line.
|
|
51
46
|
*/
|
|
52
47
|
export declare function firstDiscardedLine(content: string): number | undefined;
|
|
48
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { parseEnv } from "node:util";
|
|
4
|
-
|
|
4
|
+
const DEFAULT_ENV_MODE = "development";
|
|
5
5
|
export class AvEnvFileError extends Error {
|
|
6
6
|
filePath;
|
|
7
7
|
reason;
|
|
@@ -15,7 +15,7 @@ export class AvEnvFileError extends Error {
|
|
|
15
15
|
export function envCascadeCandidates(mode) {
|
|
16
16
|
return [`.env.${mode}.local`, `.env.${mode}`, ".env.local", ".env"];
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
function resolveEnvMode(processEnv, explicit) {
|
|
19
19
|
if (explicit !== undefined && explicit !== "")
|
|
20
20
|
return explicit;
|
|
21
21
|
const nodeEnv = processEnv.NODE_ENV;
|
|
@@ -44,7 +44,7 @@ export function resolveEnvCascade(input) {
|
|
|
44
44
|
}
|
|
45
45
|
return { mode, env: Object.freeze(env), candidates, loaded };
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
function readEnvFileFromDisk(filePath) {
|
|
48
48
|
try {
|
|
49
49
|
return readFileSync(filePath, "utf8");
|
|
50
50
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ClientModuleStyle, ImportFileExtension, ModuleFormat } from "../emit/module-style.interface.js";
|
|
3
|
-
import { type LocatedTsconfig } from "./tsconfig.locator.js";
|
|
1
|
+
import type { ClientModuleStyle } from "../emit/module-style.interface.js";
|
|
4
2
|
/** What the run follows, and where it read it from. */
|
|
5
3
|
export interface ResolvedModuleStyle extends ClientModuleStyle {
|
|
6
4
|
/** The tsconfig the style was inferred from. */
|
|
7
5
|
readonly tsconfig: string;
|
|
8
6
|
}
|
|
9
|
-
|
|
7
|
+
interface ModuleStyleInput {
|
|
10
8
|
/** The absolute `generateAt`. */
|
|
11
9
|
readonly generateAt: string;
|
|
12
10
|
/** The generated entry file, absolute: the file the project must include. */
|
|
@@ -23,5 +21,4 @@ export interface ModuleStyleInput {
|
|
|
23
21
|
export declare function resolveModuleStyle(input: ModuleStyleInput): ResolvedModuleStyle;
|
|
24
22
|
/** The refusal of a project with no tsconfig: a JavaScript project. */
|
|
25
23
|
export declare function noTsconfigRefusal(generateAt: string): string;
|
|
26
|
-
export
|
|
27
|
-
export declare function moduleFormatOf(tsconfig: LocatedTsconfig, generateAt: string): ModuleFormat;
|
|
24
|
+
export {};
|
|
@@ -20,7 +20,7 @@ export function noTsconfigRefusal(generateAt) {
|
|
|
20
20
|
"(`npx tsc --init` writes one), or, if it has one this search does not find, name it with `tsconfigFile` " +
|
|
21
21
|
"in your framework.client config. Nothing was written.");
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
function importFileExtensionOf(config) {
|
|
24
24
|
const options = config.compilerOptions;
|
|
25
25
|
if (options?.allowImportingTsExtensions ||
|
|
26
26
|
options?.rewriteRelativeImportExtensions) {
|
|
@@ -32,7 +32,7 @@ export function importFileExtensionOf(config) {
|
|
|
32
32
|
? ""
|
|
33
33
|
: "js";
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
function moduleFormatOf(tsconfig, generateAt) {
|
|
36
36
|
const module = tsconfig.config.compilerOptions?.module?.toLowerCase();
|
|
37
37
|
if (module === undefined || module === "") {
|
|
38
38
|
return "esm";
|