@jay-framework/fullstack-component 0.15.6 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +109 -1
- package/dist/index.js +61 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -445,6 +445,34 @@ type ServiceResolver = (markers: any[]) => any[];
|
|
|
445
445
|
declare global {
|
|
446
446
|
var __JAY_SERVICE_RESOLVER__: ServiceResolver | undefined;
|
|
447
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* Represents a file in a Jay action.
|
|
450
|
+
*
|
|
451
|
+
* On the **client**, browser `File` and `Blob` objects are assignable to this type
|
|
452
|
+
* (they have `name`, `type`, `size`). The framework converts them to FormData automatically.
|
|
453
|
+
*
|
|
454
|
+
* On the **server**, the framework populates `path` with a temp file location.
|
|
455
|
+
* The temp file is cleaned up after the handler returns.
|
|
456
|
+
*/
|
|
457
|
+
interface JayFile {
|
|
458
|
+
/** Original filename */
|
|
459
|
+
name: string;
|
|
460
|
+
/** MIME type */
|
|
461
|
+
type: string;
|
|
462
|
+
/** File size in bytes */
|
|
463
|
+
size: number;
|
|
464
|
+
/** Absolute path to the temp file on disk (server-side only, always present in handlers) */
|
|
465
|
+
path?: string;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Options for file upload support.
|
|
469
|
+
*/
|
|
470
|
+
interface FileUploadOptions {
|
|
471
|
+
/** Maximum file size in bytes (default: 10MB) */
|
|
472
|
+
maxFileSize?: number;
|
|
473
|
+
/** Maximum number of files (default: 10) */
|
|
474
|
+
maxFiles?: number;
|
|
475
|
+
}
|
|
448
476
|
/**
|
|
449
477
|
* Supported HTTP methods for actions and queries.
|
|
450
478
|
*/
|
|
@@ -499,6 +527,10 @@ interface JayActionDefinition<Input, Output, Services extends any[]> {
|
|
|
499
527
|
cacheOptions?: CacheOptions;
|
|
500
528
|
/** Service markers for dependency injection */
|
|
501
529
|
services: ServiceMarkers<Services>;
|
|
530
|
+
/** Whether this action accepts file uploads (DL#131) */
|
|
531
|
+
acceptsFiles?: boolean;
|
|
532
|
+
/** File upload options (DL#131) */
|
|
533
|
+
fileOptions?: FileUploadOptions;
|
|
502
534
|
/** The handler function */
|
|
503
535
|
handler: (input: Input, ...services: Services) => Promise<Output>;
|
|
504
536
|
}
|
|
@@ -518,6 +550,11 @@ interface JayActionBuilder<Services extends any[], Input, Output, DefaultMethod
|
|
|
518
550
|
* Enable caching (typically for GET requests).
|
|
519
551
|
*/
|
|
520
552
|
withCaching(options?: CacheOptions): JayActionBuilder<Services, Input, Output, DefaultMethod>;
|
|
553
|
+
/**
|
|
554
|
+
* Mark this action as accepting file uploads (DL#131).
|
|
555
|
+
* The handler will receive JayFile objects for file fields.
|
|
556
|
+
*/
|
|
557
|
+
withFiles(options?: FileUploadOptions): JayActionBuilder<Services, Input, Output, DefaultMethod>;
|
|
521
558
|
/**
|
|
522
559
|
* Define the handler function. Input and output types are inferred from the handler signature.
|
|
523
560
|
*/
|
|
@@ -570,6 +607,77 @@ type ActionOutput<T> = T extends JayAction<any, infer O> ? O : never;
|
|
|
570
607
|
* Check if a value is a JayAction.
|
|
571
608
|
*/
|
|
572
609
|
declare function isJayAction(value: unknown): value is JayAction<unknown, unknown>;
|
|
610
|
+
/**
|
|
611
|
+
* A callable streaming action that returns an async iterable of chunks.
|
|
612
|
+
* Server handler is an async generator; client receives chunks via NDJSON.
|
|
613
|
+
*/
|
|
614
|
+
interface JayStreamAction<Input, Chunk> {
|
|
615
|
+
/** Call the action — returns async iterable of chunks */
|
|
616
|
+
(input: Input): AsyncIterable<Chunk>;
|
|
617
|
+
/** Unique action name for routing */
|
|
618
|
+
readonly actionName: string;
|
|
619
|
+
/** HTTP method (always POST for streaming) */
|
|
620
|
+
readonly method: 'POST';
|
|
621
|
+
/** Streaming flag */
|
|
622
|
+
readonly isStreaming: true;
|
|
623
|
+
/** Internal marker for type identification */
|
|
624
|
+
readonly _brand: 'JayStreamAction';
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Internal definition for server-side registration of streaming actions.
|
|
628
|
+
*/
|
|
629
|
+
interface JayStreamActionDefinition<Input, Chunk, Services extends any[]> {
|
|
630
|
+
actionName: string;
|
|
631
|
+
method: 'POST';
|
|
632
|
+
isStreaming: true;
|
|
633
|
+
services: ServiceMarkers<Services>;
|
|
634
|
+
/** Whether this action accepts file uploads (DL#131) */
|
|
635
|
+
acceptsFiles?: boolean;
|
|
636
|
+
/** File upload options (DL#131) */
|
|
637
|
+
fileOptions?: FileUploadOptions;
|
|
638
|
+
handler: (input: Input, ...services: Services) => AsyncIterable<Chunk>;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Builder interface for streaming actions.
|
|
642
|
+
*/
|
|
643
|
+
interface JayStreamBuilder<Services extends any[]> {
|
|
644
|
+
withServices<NewServices extends any[]>(...services: ServiceMarkers<NewServices>): JayStreamBuilder<NewServices>;
|
|
645
|
+
/**
|
|
646
|
+
* Mark this streaming action as accepting file uploads (DL#131).
|
|
647
|
+
*/
|
|
648
|
+
withFiles(options?: FileUploadOptions): JayStreamBuilder<Services>;
|
|
649
|
+
withHandler<I, C>(handler: (input: I, ...services: Services) => AsyncIterable<C>): JayStreamAction<I, C> & JayStreamActionDefinition<I, C, Services>;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Create a streaming action that yields chunks via an async generator.
|
|
653
|
+
* Use for paginated data, long-running operations, or any streaming response.
|
|
654
|
+
*
|
|
655
|
+
* @param name - Unique action name (e.g., 'routes.discoverParams')
|
|
656
|
+
*
|
|
657
|
+
* @example
|
|
658
|
+
* ```typescript
|
|
659
|
+
* export const discoverParams = makeJayStream('routes.discoverParams')
|
|
660
|
+
* .withServices(PRODUCTS_SERVICE)
|
|
661
|
+
* .withHandler(async function* (input: { route: string }, productsService) {
|
|
662
|
+
* let page = 1;
|
|
663
|
+
* while (true) {
|
|
664
|
+
* const products = await productsService.list({ page, pageSize: 100 });
|
|
665
|
+
* yield products.map(p => ({ slug: p.slug }));
|
|
666
|
+
* if (!products.hasMore) break;
|
|
667
|
+
* page++;
|
|
668
|
+
* }
|
|
669
|
+
* });
|
|
670
|
+
* ```
|
|
671
|
+
*/
|
|
672
|
+
declare function makeJayStream(name: string): JayStreamBuilder<[]>;
|
|
673
|
+
/**
|
|
674
|
+
* Check if a value is a JayStreamAction.
|
|
675
|
+
*/
|
|
676
|
+
declare function isJayStreamAction(value: unknown): value is JayStreamAction<unknown, unknown>;
|
|
677
|
+
/**
|
|
678
|
+
* Extract the chunk type from a JayStreamAction.
|
|
679
|
+
*/
|
|
680
|
+
type StreamChunk<T> = T extends JayStreamAction<any, infer C> ? C : never;
|
|
573
681
|
|
|
574
682
|
/**
|
|
575
683
|
* Builder for plugin/project initialization with type-safe server-to-client data flow.
|
|
@@ -673,4 +781,4 @@ declare function makeJayInit(key?: string): JayInitBuilder<void>;
|
|
|
673
781
|
*/
|
|
674
782
|
declare function isJayInit(obj: unknown): obj is JayInit<any>;
|
|
675
783
|
|
|
676
|
-
export { ActionError, type ActionInput, type ActionOutput, type AnyFastRenderResult, type AnyJayStackComponentDefinition, type AnySlowlyRenderResult, type Builder, type CacheOptions, type ClientError4xx, type ContractGeneratorFunction, type DynamicContractGenerator, type DynamicContractProps, type FastRenderResult, type GeneratedContractYaml, type HeadTag, type HttpMethod, type JayAction, type JayActionBuilder, type JayActionDefinition, type JayInit, type JayInitBuilder, type JayInitBuilderWithServer, type JayStackComponentDefinition, type LoadParams, type PageProps, type PartialRender, type PhaseOutput, type PipelineFactory, type Redirect3xx, type RenderFast, type RenderOutcome, RenderPipeline, type RenderSlowly, type RequestQuery, type ServerError5xx, type ServiceInstances, type ServiceMarker, type ServiceMarkers, type Signals, type SlowlyRenderResult, type UrlParams, badRequest, clientError4xx, createJayService, forbidden, isJayAction, isJayInit, makeContractGenerator, makeJayAction, makeJayInit, makeJayQuery, makeJayStackComponent, notFound, partialRender, phaseOutput, redirect3xx, serverError5xx, unauthorized };
|
|
784
|
+
export { ActionError, type ActionInput, type ActionOutput, type AnyFastRenderResult, type AnyJayStackComponentDefinition, type AnySlowlyRenderResult, type Builder, type CacheOptions, type ClientError4xx, type ContractGeneratorFunction, type DynamicContractGenerator, type DynamicContractProps, type FastRenderResult, type FileUploadOptions, type GeneratedContractYaml, type HeadTag, type HttpMethod, type JayAction, type JayActionBuilder, type JayActionDefinition, type JayFile, type JayInit, type JayInitBuilder, type JayInitBuilderWithServer, type JayStackComponentDefinition, type JayStreamAction, type JayStreamActionDefinition, type JayStreamBuilder, type LoadParams, type PageProps, type PartialRender, type PhaseOutput, type PipelineFactory, type Redirect3xx, type RenderFast, type RenderOutcome, RenderPipeline, type RenderSlowly, type RequestQuery, type ServerError5xx, type ServiceInstances, type ServiceMarker, type ServiceMarkers, type Signals, type SlowlyRenderResult, type StreamChunk, type UrlParams, badRequest, clientError4xx, createJayService, forbidden, isJayAction, isJayInit, isJayStreamAction, makeContractGenerator, makeJayAction, makeJayInit, makeJayQuery, makeJayStackComponent, makeJayStream, notFound, partialRender, phaseOutput, redirect3xx, serverError5xx, unauthorized };
|
package/dist/index.js
CHANGED
|
@@ -364,6 +364,8 @@ class JayActionBuilderImpl {
|
|
|
364
364
|
__publicField(this, "_services", []);
|
|
365
365
|
__publicField(this, "_method");
|
|
366
366
|
__publicField(this, "_cacheOptions");
|
|
367
|
+
__publicField(this, "_acceptsFiles", false);
|
|
368
|
+
__publicField(this, "_fileOptions");
|
|
367
369
|
this._actionName = _actionName;
|
|
368
370
|
this._method = defaultMethod;
|
|
369
371
|
}
|
|
@@ -379,11 +381,18 @@ class JayActionBuilderImpl {
|
|
|
379
381
|
this._cacheOptions = options ?? { maxAge: 60 };
|
|
380
382
|
return this;
|
|
381
383
|
}
|
|
384
|
+
withFiles(options) {
|
|
385
|
+
this._acceptsFiles = true;
|
|
386
|
+
this._fileOptions = options;
|
|
387
|
+
return this;
|
|
388
|
+
}
|
|
382
389
|
withHandler(handler) {
|
|
383
390
|
const actionName = this._actionName;
|
|
384
391
|
const method = this._method;
|
|
385
392
|
const cacheOptions = this._cacheOptions;
|
|
386
393
|
const serviceMarkers = this._services;
|
|
394
|
+
const acceptsFiles = this._acceptsFiles;
|
|
395
|
+
const fileOptions = this._fileOptions;
|
|
387
396
|
const action = Object.assign(
|
|
388
397
|
(input) => {
|
|
389
398
|
const resolver = globalThis.__JAY_SERVICE_RESOLVER__;
|
|
@@ -396,7 +405,9 @@ class JayActionBuilderImpl {
|
|
|
396
405
|
cacheOptions,
|
|
397
406
|
services: serviceMarkers,
|
|
398
407
|
handler,
|
|
399
|
-
_brand: "JayAction"
|
|
408
|
+
_brand: "JayAction",
|
|
409
|
+
...acceptsFiles && { acceptsFiles: true },
|
|
410
|
+
...fileOptions && { fileOptions }
|
|
400
411
|
}
|
|
401
412
|
);
|
|
402
413
|
return action;
|
|
@@ -411,6 +422,53 @@ function makeJayQuery(name) {
|
|
|
411
422
|
function isJayAction(value) {
|
|
412
423
|
return typeof value === "function" && value._brand === "JayAction" && typeof value.actionName === "string";
|
|
413
424
|
}
|
|
425
|
+
class JayStreamBuilderImpl {
|
|
426
|
+
constructor(_actionName) {
|
|
427
|
+
__publicField(this, "_services", []);
|
|
428
|
+
__publicField(this, "_acceptsFiles", false);
|
|
429
|
+
__publicField(this, "_fileOptions");
|
|
430
|
+
this._actionName = _actionName;
|
|
431
|
+
}
|
|
432
|
+
withServices(...services) {
|
|
433
|
+
this._services = services;
|
|
434
|
+
return this;
|
|
435
|
+
}
|
|
436
|
+
withFiles(options) {
|
|
437
|
+
this._acceptsFiles = true;
|
|
438
|
+
this._fileOptions = options;
|
|
439
|
+
return this;
|
|
440
|
+
}
|
|
441
|
+
withHandler(handler) {
|
|
442
|
+
const actionName = this._actionName;
|
|
443
|
+
const serviceMarkers = this._services;
|
|
444
|
+
const acceptsFiles = this._acceptsFiles;
|
|
445
|
+
const fileOptions = this._fileOptions;
|
|
446
|
+
const action = Object.assign(
|
|
447
|
+
(input) => {
|
|
448
|
+
const resolver = globalThis.__JAY_SERVICE_RESOLVER__;
|
|
449
|
+
const resolvedServices = resolver ? resolver(serviceMarkers) : [];
|
|
450
|
+
return handler(input, ...resolvedServices);
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
actionName,
|
|
454
|
+
method: "POST",
|
|
455
|
+
isStreaming: true,
|
|
456
|
+
services: serviceMarkers,
|
|
457
|
+
handler,
|
|
458
|
+
_brand: "JayStreamAction",
|
|
459
|
+
...acceptsFiles && { acceptsFiles: true },
|
|
460
|
+
...fileOptions && { fileOptions }
|
|
461
|
+
}
|
|
462
|
+
);
|
|
463
|
+
return action;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
function makeJayStream(name) {
|
|
467
|
+
return new JayStreamBuilderImpl(name);
|
|
468
|
+
}
|
|
469
|
+
function isJayStreamAction(value) {
|
|
470
|
+
return typeof value === "function" && value._brand === "JayStreamAction" && typeof value.actionName === "string";
|
|
471
|
+
}
|
|
414
472
|
function makeJayInit(key) {
|
|
415
473
|
const resolvedKey = key ?? "__JAY_INIT_KEY__";
|
|
416
474
|
return {
|
|
@@ -455,11 +513,13 @@ export {
|
|
|
455
513
|
forbidden,
|
|
456
514
|
isJayAction,
|
|
457
515
|
isJayInit,
|
|
516
|
+
isJayStreamAction,
|
|
458
517
|
makeContractGenerator,
|
|
459
518
|
makeJayAction,
|
|
460
519
|
makeJayInit,
|
|
461
520
|
makeJayQuery,
|
|
462
521
|
makeJayStackComponent,
|
|
522
|
+
makeJayStream,
|
|
463
523
|
notFound,
|
|
464
524
|
partialRender,
|
|
465
525
|
phaseOutput,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/fullstack-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"test:watch": "vitest"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@jay-framework/component": "^0.
|
|
30
|
-
"@jay-framework/runtime": "^0.
|
|
29
|
+
"@jay-framework/component": "^0.16.1",
|
|
30
|
+
"@jay-framework/runtime": "^0.16.1"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@jay-framework/dev-environment": "^0.
|
|
34
|
-
"@jay-framework/jay-cli": "^0.
|
|
33
|
+
"@jay-framework/dev-environment": "^0.16.1",
|
|
34
|
+
"@jay-framework/jay-cli": "^0.16.1",
|
|
35
35
|
"@types/express": "^5.0.2",
|
|
36
36
|
"@types/node": "^22.15.21",
|
|
37
37
|
"nodemon": "^3.0.3",
|