@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
|
@@ -231,13 +231,18 @@ function copyJson(side: Side, value: unknown, path: Path, ancestors: Set<object>
|
|
|
231
231
|
if (Array.isArray(value)) {
|
|
232
232
|
const items: unknown[] = [];
|
|
233
233
|
for (let index = 0; index < value.length; index += 1) {
|
|
234
|
-
|
|
234
|
+
// An undefined element (or a hole) is null, as JSON writes it (rc.2).
|
|
235
|
+
const item = value[index];
|
|
236
|
+
items.push(item === undefined ? null : copyJson(side, item, [...path, index], ancestors));
|
|
235
237
|
}
|
|
236
238
|
copy = items;
|
|
237
239
|
} else {
|
|
238
|
-
// fromEntries defines each key, so "__proto__" stays an own key.
|
|
240
|
+
// fromEntries defines each key, so "__proto__" stays an own key. A key holding
|
|
241
|
+
// undefined is left out, as JSON leaves it out (rc.2).
|
|
239
242
|
copy = Object.fromEntries(
|
|
240
|
-
Object.entries(value)
|
|
243
|
+
Object.entries(value)
|
|
244
|
+
.filter(([, member]) => member !== undefined)
|
|
245
|
+
.map(([key, member]) => [key, copyJson(side, member, [...path, key], ancestors)]),
|
|
241
246
|
);
|
|
242
247
|
}
|
|
243
248
|
ancestors.delete(value);
|
|
@@ -271,8 +276,10 @@ function writeWireJson(value: unknown, path: Path, ancestors: Set<object>): stri
|
|
|
271
276
|
if (Array.isArray(value)) {
|
|
272
277
|
const items: string[] = [];
|
|
273
278
|
for (let index = 0; index < value.length; index += 1) {
|
|
274
|
-
// An undefined element is
|
|
275
|
-
|
|
279
|
+
// An undefined element (or a hole) is null, as JSON writes it (rc.2): the
|
|
280
|
+
// server reads the same value from an in-process caller.
|
|
281
|
+
const item = value[index];
|
|
282
|
+
items.push(item === undefined ? "null" : writeWireJson(item, [...path, index], ancestors));
|
|
276
283
|
}
|
|
277
284
|
text = "[" + items.join(",") + "]";
|
|
278
285
|
} else {
|
|
@@ -310,7 +317,8 @@ export function decodeScalar(scalar: AvBuiltInScalar, wire: unknown): unknown {
|
|
|
310
317
|
/**
|
|
311
318
|
* The JSON text of a request body whose scalars are already encoded. Every
|
|
312
319
|
* undefined property is stripped, at every depth (an optional property is
|
|
313
|
-
* omitted, never sent),
|
|
320
|
+
* omitted, never sent), an undefined array element is null, as JSON.stringify
|
|
321
|
+
* writes both, and null is kept as the explicit value it is.
|
|
314
322
|
* Anything else that is not JSON-safe is refused rather than coerced: it means a
|
|
315
323
|
* value escaped its scalar codec.
|
|
316
324
|
*/
|
|
@@ -347,6 +355,215 @@ export function readArgument<T>(path: Path, read: () => T): T {
|
|
|
347
355
|
}
|
|
348
356
|
}
|
|
349
357
|
|
|
358
|
+
/** Where each relation directive holds the records its target writes; its other members select. */
|
|
359
|
+
export const RECORD_SITES: { readonly [directive: string]: readonly (string | undefined)[] } = {
|
|
360
|
+
$create: [undefined],
|
|
361
|
+
$connect: [],
|
|
362
|
+
$connectOrCreate: ["create"],
|
|
363
|
+
$disconnect: [],
|
|
364
|
+
$set: [],
|
|
365
|
+
$update: ["data"],
|
|
366
|
+
$delete: [],
|
|
367
|
+
$upsert: ["create", "update"],
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
/** The members of an operation's arguments that hold its write records. */
|
|
371
|
+
export function writeKeysOf(family: string): readonly string[] {
|
|
372
|
+
return family === "create" || family === "update" ? ["data"] : family === "upsert" ? ["create", "update"] : [];
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** The code an unsent value is refused with: the server's for that place. */
|
|
376
|
+
export type UnsentCode = "V1001" | "V1007" | "V1009";
|
|
377
|
+
|
|
378
|
+
/** One value a request would leave out: where it is, and the server's code for it. */
|
|
379
|
+
export interface UnsentValue {
|
|
380
|
+
readonly path: Path;
|
|
381
|
+
readonly code: UnsentCode;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Every undefined value an operation's arguments hold where leaving it out would
|
|
386
|
+
* reach more rows than the caller wrote, in argument order, each with the code the
|
|
387
|
+
* server answers it with:
|
|
388
|
+
*
|
|
389
|
+
* - inside a filter, a unique selector or a cursor, at any depth: a where (AND, OR,
|
|
390
|
+
* NOT, a relation filter, an operator object, an in list), a cursor, the where and
|
|
391
|
+
* cursor of a relation that select or include reads, and a nested write's
|
|
392
|
+
* selectors (what $connect, $disconnect, $set and $delete name, and the where of
|
|
393
|
+
* $update, $upsert and $connectOrCreate) (V1001);
|
|
394
|
+
* - a where, cursor, limit or offset that is itself undefined, as a call's or a
|
|
395
|
+
* relation's argument (V1001; a unique variant's where V1007, a cursor V1009),
|
|
396
|
+
* and the where of $update (V1001), $upsert or $connectOrCreate (V1007).
|
|
397
|
+
*
|
|
398
|
+
* JSON drops an undefined value, so such a value is never sent. An undefined field
|
|
399
|
+
* of a write record is not sent, which is what leaving it out means; a projection,
|
|
400
|
+
* an order or a directive left undefined is left out as well.
|
|
401
|
+
*/
|
|
402
|
+
export function unsentValues(
|
|
403
|
+
table: DecodeTable,
|
|
404
|
+
resource: string,
|
|
405
|
+
family: string,
|
|
406
|
+
variant: string,
|
|
407
|
+
args: unknown,
|
|
408
|
+
): UnsentValue[] {
|
|
409
|
+
const found: UnsentValue[] = [];
|
|
410
|
+
const ancestors = new Set<object>();
|
|
411
|
+
|
|
412
|
+
const listAt = (value: unknown, path: Path): readonly unknown[] | undefined =>
|
|
413
|
+
typeof value === "object" && value !== null && readArgument(path, () => Array.isArray(value))
|
|
414
|
+
? (value as readonly unknown[])
|
|
415
|
+
: undefined;
|
|
416
|
+
const recordAt = (value: unknown, path: Path): Readonly<Record<string, unknown>> | undefined =>
|
|
417
|
+
typeof value === "object" && value !== null && readArgument(path, () => !Array.isArray(value) && isPlainRecord(value))
|
|
418
|
+
? (value as Readonly<Record<string, unknown>>)
|
|
419
|
+
: undefined;
|
|
420
|
+
|
|
421
|
+
// Visits each member of a container in order (each entry of a list, each key of a
|
|
422
|
+
// record), undefined ones only when asked; a container met again on its own
|
|
423
|
+
// ancestry is not walked again, and the encoder refuses it.
|
|
424
|
+
const each = (
|
|
425
|
+
container: readonly unknown[] | Readonly<Record<string, unknown>>,
|
|
426
|
+
path: Path,
|
|
427
|
+
withUndefined: boolean,
|
|
428
|
+
visit: (key: string | number, value: unknown, at: Path) => void,
|
|
429
|
+
): void => {
|
|
430
|
+
if (ancestors.has(container)) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
ancestors.add(container);
|
|
434
|
+
const keys: readonly (string | number)[] = Array.isArray(container)
|
|
435
|
+
? Array.from({ length: readArgument(path, () => container.length) }, (_, index) => index)
|
|
436
|
+
: readArgument(path, () => Object.keys(container));
|
|
437
|
+
for (const key of keys) {
|
|
438
|
+
const at = [...path, key];
|
|
439
|
+
const value = readArgument(at, () => (container as Readonly<Record<string | number, unknown>>)[key]);
|
|
440
|
+
if (withUndefined || value !== undefined) {
|
|
441
|
+
visit(key, value, at);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
ancestors.delete(container);
|
|
445
|
+
};
|
|
446
|
+
// One entry, or each entry of a list.
|
|
447
|
+
const entries = (value: unknown, path: Path, visit: (entry: unknown, at: Path) => void): void => {
|
|
448
|
+
const list = listAt(value, path);
|
|
449
|
+
if (list === undefined) {
|
|
450
|
+
visit(value, path);
|
|
451
|
+
} else {
|
|
452
|
+
each(list, path, true, (_index, entry, at) => visit(entry, at));
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
const filter = (value: unknown, path: Path): void => {
|
|
457
|
+
if (value === undefined) {
|
|
458
|
+
found.push({ path, code: "V1001" });
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const container = listAt(value, path) ?? recordAt(value, path);
|
|
462
|
+
if (container !== undefined) {
|
|
463
|
+
each(container, path, true, (_key, member, at) => filter(member, at));
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
// A read's own arguments (a call's, or a relation's under select or include):
|
|
467
|
+
// its where and cursor are filters, its limit and offset bound what it returns.
|
|
468
|
+
const read = (key: string | number, value: unknown, at: Path, whereCode: UnsentCode, cursorCode: UnsentCode): void => {
|
|
469
|
+
if (key === "where" || key === "cursor") {
|
|
470
|
+
if (value === undefined) {
|
|
471
|
+
found.push({ path: at, code: key === "where" ? whereCode : cursorCode });
|
|
472
|
+
} else {
|
|
473
|
+
filter(value, at);
|
|
474
|
+
}
|
|
475
|
+
} else if (key === "limit" || key === "offset") {
|
|
476
|
+
if (value === undefined) {
|
|
477
|
+
found.push({ path: at, code: "V1001" });
|
|
478
|
+
}
|
|
479
|
+
} else if ((key === "select" || key === "include") && value !== undefined) {
|
|
480
|
+
projection(value, at);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
const projection = (value: unknown, path: Path): void => {
|
|
484
|
+
const list = listAt(value, path);
|
|
485
|
+
if (list === undefined) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
each(list, path, false, (_index, entry, at) => {
|
|
489
|
+
const relations = recordAt(entry, at);
|
|
490
|
+
if (relations === undefined) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
each(relations, at, false, (_relation, nested, nestedAt) => {
|
|
494
|
+
const args = recordAt(nested, nestedAt);
|
|
495
|
+
if (args !== undefined) {
|
|
496
|
+
each(args, nestedAt, true, (key, member, memberAt) => read(key, member, memberAt, "V1001", "V1009"));
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
};
|
|
501
|
+
const writeRecord = (target: string, value: unknown, path: Path): void => {
|
|
502
|
+
const record = recordAt(value, path);
|
|
503
|
+
if (record === undefined) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const fields = Object.hasOwn(table, target) ? table[target] : undefined;
|
|
507
|
+
each(record, path, false, (key, member, at) => {
|
|
508
|
+
const decoding = fields !== undefined && Object.hasOwn(fields, key) ? fields[key as string] : undefined;
|
|
509
|
+
if (typeof decoding === "object") {
|
|
510
|
+
relationWrite(decoding.relation, member, at);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
};
|
|
514
|
+
const relationWrite = (target: string, value: unknown, path: Path): void => {
|
|
515
|
+
const directives = recordAt(value, path);
|
|
516
|
+
if (directives === undefined) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
each(directives, path, false, (directive, operand, at) => {
|
|
520
|
+
const sites = Object.hasOwn(RECORD_SITES, directive) ? RECORD_SITES[directive as string] : undefined;
|
|
521
|
+
if (sites === undefined) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
if (sites.length === 0) {
|
|
525
|
+
filter(operand, at);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
entries(operand, at, (entry, entryAt) => {
|
|
529
|
+
if (sites.includes(undefined)) {
|
|
530
|
+
writeRecord(target, entry, entryAt);
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const parts = recordAt(entry, entryAt);
|
|
534
|
+
if (parts !== undefined) {
|
|
535
|
+
each(parts, entryAt, true, (key, member, memberAt) => {
|
|
536
|
+
if (sites.includes(key as string)) {
|
|
537
|
+
writeRecord(target, member, memberAt);
|
|
538
|
+
} else if (member !== undefined) {
|
|
539
|
+
filter(member, memberAt);
|
|
540
|
+
} else if (key === "where") {
|
|
541
|
+
found.push({ path: memberAt, code: directive === "$update" ? "V1001" : "V1007" });
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
});
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
const root = recordAt(args, []);
|
|
550
|
+
if (root !== undefined) {
|
|
551
|
+
const writeKeys = writeKeysOf(family);
|
|
552
|
+
const whereCode: UnsentCode = variant === "unique" ? "V1007" : "V1001";
|
|
553
|
+
const cursorCode: UnsentCode = family === "find" && variant === "many" ? "V1009" : "V1001";
|
|
554
|
+
each(root, [], true, (key, value, at) => {
|
|
555
|
+
if (writeKeys.includes(key as string)) {
|
|
556
|
+
if (value !== undefined) {
|
|
557
|
+
entries(value, at, (entry, entryAt) => writeRecord(resource, entry, entryAt));
|
|
558
|
+
}
|
|
559
|
+
} else {
|
|
560
|
+
read(key, value, at, whereCode, cursorCode);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
return found;
|
|
565
|
+
}
|
|
566
|
+
|
|
350
567
|
/** How encodeValue treats an object: a scalar's runtime class, a container, or neither. */
|
|
351
568
|
function objectKind(value: object): "datetime" | "decimal" | "bytes" | "container" | "other" {
|
|
352
569
|
if (value instanceof Date) {
|
|
@@ -212,7 +212,7 @@ function transactionModuleSource(from) {
|
|
|
212
212
|
return `import { encodeArguments, readArgument, serializeWireBody } from ${from("./codec")};
|
|
213
213
|
import { type AvCause, type AvError, frameworkErrorOf } from ${from("./errors")};
|
|
214
214
|
import { fingerprintOf } from ${from("./fingerprint")};
|
|
215
|
-
import { type AvCallOptions, executePlan, type TransportConnection } from ${from("./transport")};
|
|
215
|
+
import { type AvCallOptions, executePlan, refuseUnsentValues, type TransportConnection } from ${from("./transport")};
|
|
216
216
|
|
|
217
217
|
/**
|
|
218
218
|
* The deferred transaction builder and runner: \`avClient.tx\` defers an operation
|
|
@@ -384,8 +384,11 @@ export type PlanCheck = (
|
|
|
384
384
|
* generated client, one handle twice (AvValidationError A2004 / V1001 at
|
|
385
385
|
* ["operations", i]: the entry itself); a reference to a handle not in the list (AvValidationError A2007 /
|
|
386
386
|
* V1010 at its \`$ref\`); a handle whose arguments could not be read when it was
|
|
387
|
-
* built (the TypeError naming where);
|
|
388
|
-
*
|
|
387
|
+
* built (the TypeError naming where); a step holding an undefined value JSON would
|
|
388
|
+
* leave out to widen it (AvValidationError A2004, as refuseUnsentValues states it,
|
|
389
|
+
* the step named);
|
|
390
|
+
* and, when \`check\` is given, a step whose values break a field check
|
|
391
|
+
* (AvValidationError A2004, as the server answers it).
|
|
389
392
|
*/
|
|
390
393
|
export async function runTransaction(
|
|
391
394
|
connection: TransportConnection,
|
|
@@ -431,6 +434,7 @@ export async function runTransaction(
|
|
|
431
434
|
});
|
|
432
435
|
}
|
|
433
436
|
}
|
|
437
|
+
refuseUnsentValues(record.resource, record.family, record.variant, record.args, ["operations", index, "args"], index);
|
|
434
438
|
}
|
|
435
439
|
|
|
436
440
|
check?.(records);
|
package/dist/generate.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type ProcessEnvInput } from "./config/env.cascade.js";
|
|
|
3
3
|
import { type ContractFetch } from "./contract/contract.fetcher.js";
|
|
4
4
|
import { type EmittedFilePath } from "./emit/emitted-tree.interface.js";
|
|
5
5
|
import type { OutputCheck, TypeScriptResolver } from "./output/output.validator.js";
|
|
6
|
-
|
|
6
|
+
interface ClientGenerationInput {
|
|
7
7
|
/** The project directory: where `framework.client.ts` and the `.env` files are. */
|
|
8
8
|
readonly directory: string;
|
|
9
9
|
/** A snapshot of the process environment. Never mutated. */
|
|
@@ -25,7 +25,7 @@ export interface ClientGenerationInput {
|
|
|
25
25
|
readonly step?: GenerationStep;
|
|
26
26
|
}
|
|
27
27
|
/** Runs one phase of a generation under its title, resolving to what it returns. */
|
|
28
|
-
|
|
28
|
+
type GenerationStep = <T>(title: string, body: () => Promise<T> | T) => Promise<T>;
|
|
29
29
|
export interface ClientGenerated {
|
|
30
30
|
readonly kind: "generated";
|
|
31
31
|
/** The shared directory the client was generated into. */
|
|
@@ -79,3 +79,4 @@ export type ClientGenerationOutcome = ClientGenerated | ClientUpToDate | Foreign
|
|
|
79
79
|
* is a defect.
|
|
80
80
|
*/
|
|
81
81
|
export declare function generateClient(input: ClientGenerationInput): Promise<ClientGenerationOutcome>;
|
|
82
|
+
export {};
|
package/dist/generate.js
CHANGED
|
@@ -51,7 +51,7 @@ export async function generateClient(input) {
|
|
|
51
51
|
const emission = emitClientTree(contract, config.entrypoint, {
|
|
52
52
|
importFileExtension: style.importFileExtension,
|
|
53
53
|
moduleFormat: style.moduleFormat,
|
|
54
|
-
});
|
|
54
|
+
}, undefined, config.accessOrigins);
|
|
55
55
|
return {
|
|
56
56
|
emission,
|
|
57
57
|
upToDate: notModified &&
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The tagged form a dehydrated value takes: `{ [tagKey]: <tag>, [valueKey]: <wire form> }`. */
|
|
2
|
+
export declare const HYDRATION_FORMAT: {
|
|
3
|
+
/** The key a tag is under. */
|
|
4
|
+
readonly tagKey: "$av";
|
|
5
|
+
/** The key the tagged value's wire form is under. */
|
|
6
|
+
readonly valueKey: "v";
|
|
7
|
+
/** The tag of a plain object that holds `tagKey` as data. */
|
|
8
|
+
readonly objectTag: "object";
|
|
9
|
+
/** The scalars a value is tagged as: those whose runtime values JSON does not carry. */
|
|
10
|
+
readonly scalarTags: readonly ["bigint", "bytes", "datetime", "decimal"];
|
|
11
|
+
};
|
|
@@ -2,11 +2,11 @@ import type { ClientInitAnswers } from "./client-init.questions.js";
|
|
|
2
2
|
import type { ClientProject } from "./client-project.inspector.js";
|
|
3
3
|
export declare const GENERATE_SCRIPT = "avclient:generate";
|
|
4
4
|
/** One change to a project file: its new content, or `undefined` to remove it. */
|
|
5
|
-
|
|
5
|
+
type ClientInitWrite = {
|
|
6
6
|
readonly path: string;
|
|
7
7
|
readonly content: string | undefined;
|
|
8
8
|
};
|
|
9
|
-
|
|
9
|
+
type ClientInitPlan = {
|
|
10
10
|
readonly keeping: readonly ClientInitWrite[];
|
|
11
11
|
readonly replacing: readonly ClientInitWrite[];
|
|
12
12
|
readonly conflicts: readonly string[];
|
|
@@ -16,3 +16,4 @@ export declare function planClientInit(input: {
|
|
|
16
16
|
readonly answers: ClientInitAnswers;
|
|
17
17
|
readonly clientVersion: string;
|
|
18
18
|
}): ClientInitPlan;
|
|
19
|
+
export {};
|
|
@@ -15,18 +15,7 @@ export declare class AvClientInitAnswerError extends Error {
|
|
|
15
15
|
export declare class AvClientInitUnansweredError extends Error {
|
|
16
16
|
readonly name = "AvClientInitUnansweredError";
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
readonly id: QuestionId;
|
|
20
|
-
readonly flag: string;
|
|
21
|
-
readonly placeholder: string;
|
|
22
|
-
readonly label: string;
|
|
23
|
-
readonly defaultFor: (detectedPackageManager: PackageManager) => string;
|
|
24
|
-
/** @throws AvClientInitAnswerError */
|
|
25
|
-
readonly parse: (raw: string) => string;
|
|
26
|
-
};
|
|
27
|
-
export declare const DEFAULT_ENV_VAR = "AVENTARA_API_URL";
|
|
28
|
-
export declare const CLIENT_INIT_QUESTIONS: readonly ClientInitQuestion[];
|
|
29
|
-
export type ClientInitSources = {
|
|
18
|
+
type ClientInitSources = {
|
|
30
19
|
readonly given: Readonly<Partial<Record<QuestionId, string>>>;
|
|
31
20
|
/** `--no-env-var`: the entrypoint is written as a literal, and no variable is asked. */
|
|
32
21
|
readonly noEnvVar: boolean;
|
|
@@ -6,8 +6,8 @@ export class AvClientInitAnswerError extends Error {
|
|
|
6
6
|
export class AvClientInitUnansweredError extends Error {
|
|
7
7
|
name = "AvClientInitUnansweredError";
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const DEFAULT_ENV_VAR = "AVENTARA_API_URL";
|
|
10
|
+
const CLIENT_INIT_QUESTIONS = [
|
|
11
11
|
{
|
|
12
12
|
id: "entrypoint",
|
|
13
13
|
flag: "--entrypoint",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@aventara/client/internal` is not public API.
|
|
3
|
+
*
|
|
4
|
+
* It holds what Aventara's own packages need from the client generator and an
|
|
5
|
+
* application does not. It carries no stability promise: any export here may
|
|
6
|
+
* change or disappear in any release, including a patch release.
|
|
7
|
+
*/
|
|
8
|
+
export type { ClientEntrypoint, EmittedEntrypoint, SameOriginEntrypoint, } from "./config/client-config.interface.js";
|
|
9
|
+
export { AvClientConfigError, sameOriginEntrypoint, } from "./config/config.resolver.js";
|
|
10
|
+
export type { EnvCascadeResolution } from "./config/env.cascade.js";
|
|
11
|
+
export { AvEnvFileError, resolveEnvCascade } from "./config/env.cascade.js";
|
|
12
|
+
export { resolveModuleStyle } from "./config/module-style.resolver.js";
|
|
13
|
+
export type { ContractAcceptance } from "./contract/contract.acceptance.js";
|
|
14
|
+
export { acceptClientContract } from "./contract/contract.acceptance.js";
|
|
15
|
+
export { accessVerbsOf } from "./emit/access.emitter.js";
|
|
16
|
+
export type { RegenerateCommand } from "./emit/banner.emitter.js";
|
|
17
|
+
export { carriesGeneratedOwnership } from "./emit/banner.emitter.js";
|
|
18
|
+
export type { ClientClassExport } from "./emit/client-tree.emitter.js";
|
|
19
|
+
export { clientEntryReExports, emitClientTree, } from "./emit/client-tree.emitter.js";
|
|
20
|
+
export type { ClientEmission, EmittedFile, EmittedTree, } from "./emit/emitted-tree.interface.js";
|
|
21
|
+
export { GENERATED_DIRECTORY } from "./emit/emitted-tree.interface.js";
|
|
22
|
+
export type { ClientModuleStyle } from "./emit/module-style.interface.js";
|
|
23
|
+
export { importSpecifier } from "./emit/module-style.interface.js";
|
|
24
|
+
export { AvGeneratedNameError } from "./emit/name.deriver.js";
|
|
25
|
+
export { HYDRATION_FORMAT } from "./hydration/hydration-tag.format.js";
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { AvClientConfigError, sameOriginEntrypoint, } from "./config/config.resolver.js";
|
|
2
|
+
export { AvEnvFileError, resolveEnvCascade } from "./config/env.cascade.js";
|
|
3
|
+
export { resolveModuleStyle } from "./config/module-style.resolver.js";
|
|
4
|
+
export { acceptClientContract } from "./contract/contract.acceptance.js";
|
|
5
|
+
export { accessVerbsOf } from "./emit/access.emitter.js";
|
|
6
|
+
export { carriesGeneratedOwnership } from "./emit/banner.emitter.js";
|
|
7
|
+
export { clientEntryReExports, emitClientTree, } from "./emit/client-tree.emitter.js";
|
|
8
|
+
export { GENERATED_DIRECTORY } from "./emit/emitted-tree.interface.js";
|
|
9
|
+
export { importSpecifier } from "./emit/module-style.interface.js";
|
|
10
|
+
export { AvGeneratedNameError } from "./emit/name.deriver.js";
|
|
11
|
+
export { HYDRATION_FORMAT } from "./hydration/hydration-tag.format.js";
|
|
@@ -14,7 +14,7 @@ export type TypeScriptResolver = () => Promise<TypeScriptCompiler | undefined>;
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function typeScriptResolverFor(specifier: string, directory: string): TypeScriptResolver;
|
|
16
16
|
export declare function projectTypeScriptResolver(generateAt: string): TypeScriptResolver;
|
|
17
|
-
export declare const MINIMUM_TYPESCRIPT = "5.
|
|
17
|
+
export declare const MINIMUM_TYPESCRIPT = "5.7.0";
|
|
18
18
|
/** How deeply the tree was judged. */
|
|
19
19
|
export type OutputCheck = "types" | "syntax" | "shape";
|
|
20
20
|
export interface OutputAccepted {
|
|
@@ -45,9 +45,8 @@ export declare const SYNTAX_CHECK_UNAVAILABLE_WARNING: string;
|
|
|
45
45
|
export declare function typeScriptWithoutCompilerApiWarning(version: string, checked: "syntax" | "shape"): string;
|
|
46
46
|
/**
|
|
47
47
|
* The warning a run carries when the project's `typescript` is older than the
|
|
48
|
-
* peer range:
|
|
49
|
-
*
|
|
50
|
-
* supported compiler gives.
|
|
48
|
+
* peer range: Aventara's types are not measured under it, so its verdict
|
|
49
|
+
* would not be the one a supported compiler gives.
|
|
51
50
|
*/
|
|
52
51
|
export declare function typeScriptBelowRangeWarning(version: string, checked: "syntax" | "shape"): string;
|
|
53
52
|
/**
|
|
@@ -24,7 +24,7 @@ export function typeScriptResolverFor(specifier, directory) {
|
|
|
24
24
|
export function projectTypeScriptResolver(generateAt) {
|
|
25
25
|
return typeScriptResolverFor("typescript", generateAt);
|
|
26
26
|
}
|
|
27
|
-
export const MINIMUM_TYPESCRIPT = "5.
|
|
27
|
+
export const MINIMUM_TYPESCRIPT = "5.7.0";
|
|
28
28
|
function meetsMinimum(version) {
|
|
29
29
|
const parts = /^(\d+)\.(\d+)\.(\d+)/.exec(version);
|
|
30
30
|
const minimum = MINIMUM_TYPESCRIPT.split(".").map(Number);
|
|
@@ -57,7 +57,7 @@ export const SYNTAX_CHECK_UNAVAILABLE_WARNING = "neither `typescript` nor Node's
|
|
|
57
57
|
export function typeScriptWithoutCompilerApiWarning(version, checked) {
|
|
58
58
|
return (`the installed \`typescript\` ${version} has no classic compiler API (\`createProgram\`), so the generated ` +
|
|
59
59
|
`output was NOT type-checked${checked === "shape" ? " or parsed — only its shape was" : " — only its shape and syntax were"}. ` +
|
|
60
|
-
"Your project's own `tsc` checks it when it compiles; a `typescript` 5.
|
|
60
|
+
"Your project's own `tsc` checks it when it compiles; a `typescript` 5.7 to 6 restores the generator's own type check.");
|
|
61
61
|
}
|
|
62
62
|
export function typeScriptBelowRangeWarning(version, checked) {
|
|
63
63
|
return (`the installed \`typescript\` ${version} is older than ${MINIMUM_TYPESCRIPT}, the lowest @aventara/client supports, so the generated ` +
|
|
@@ -32,7 +32,7 @@ export declare function precedeDefect(defect: unknown, earlier: readonly string[
|
|
|
32
32
|
*/
|
|
33
33
|
export declare function warningsRaisedBeforeDefect(defect: unknown): readonly string[];
|
|
34
34
|
export type OutputFileSystem = Pick<typeof fsPromises, "lstat" | "mkdir" | "open" | "readdir" | "rename" | "rm" | "rmdir" | "writeFile">;
|
|
35
|
-
|
|
35
|
+
interface ClientOutputWriteInput {
|
|
36
36
|
/** What `emitClientTree` returned: the tree, and the warnings it raised. */
|
|
37
37
|
readonly emission: ClientEmission;
|
|
38
38
|
readonly generateAt: AbsolutePath;
|
|
@@ -40,7 +40,7 @@ export interface ClientOutputWriteInput {
|
|
|
40
40
|
readonly resolveTypeScript?: TypeScriptResolver;
|
|
41
41
|
readonly fileSystem?: OutputFileSystem;
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
interface ClientOutputWritten {
|
|
44
44
|
readonly generateAt: AbsolutePath;
|
|
45
45
|
readonly checked: OutputCheck;
|
|
46
46
|
readonly warnings: readonly string[];
|
|
@@ -58,3 +58,4 @@ export declare function writeClientOutput(input: ClientOutputWriteInput): Promis
|
|
|
58
58
|
*/
|
|
59
59
|
export declare function findForeignOutputContent(generateAt: AbsolutePath, fileSystem?: OutputFileSystem): Promise<readonly string[]>;
|
|
60
60
|
export declare function ownedOutputMatches(generateAt: AbsolutePath, tree: EmittedTree): Promise<boolean>;
|
|
61
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aventara/client",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.10",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "Development-time generator for Aventara typed remote clients.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
8
|
-
"node": "^22.
|
|
8
|
+
"node": "^22.23.4 || >=24.22.1"
|
|
9
9
|
},
|
|
10
10
|
"main": "./dist/index.js",
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
".": {
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
18
|
"import": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./internal": {
|
|
21
|
+
"types": "./dist/internal.d.ts",
|
|
22
|
+
"import": "./dist/internal.js"
|
|
19
23
|
}
|
|
20
24
|
},
|
|
21
25
|
"files": [
|
|
@@ -24,12 +28,12 @@
|
|
|
24
28
|
"CHANGELOG.md"
|
|
25
29
|
],
|
|
26
30
|
"dependencies": {
|
|
27
|
-
"@aventara/core": "1.0.0-rc.
|
|
31
|
+
"@aventara/core": "1.0.0-rc.10",
|
|
28
32
|
"c12": "3.3.4",
|
|
29
33
|
"get-tsconfig": "4.10.0"
|
|
30
34
|
},
|
|
31
35
|
"peerDependencies": {
|
|
32
|
-
"typescript": ">=5.
|
|
36
|
+
"typescript": ">=5.7.0"
|
|
33
37
|
},
|
|
34
38
|
"peerDependenciesMeta": {
|
|
35
39
|
"typescript": {
|
|
@@ -40,7 +44,7 @@
|
|
|
40
44
|
"access": "public"
|
|
41
45
|
},
|
|
42
46
|
"devDependencies": {
|
|
43
|
-
"@aventara/testing": "1.0.0-rc.
|
|
47
|
+
"@aventara/testing": "1.0.0-rc.10",
|
|
44
48
|
"@types/node": "24.10.1",
|
|
45
49
|
"typescript": "^5.9.2"
|
|
46
50
|
},
|