@pylonsync/functions 0.22.6 → 0.22.8
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 +1 -1
- package/dist/types.d.ts +39 -1
- package/package.json +1 -1
- package/src/index.ts +5 -0
- package/src/runtime.ts +61 -3
- package/src/types.ts +43 -1
package/dist/index.d.ts
CHANGED
|
@@ -27,4 +27,4 @@ export type { WorkflowDefinition, WorkflowRun, WorkflowRunRequest, WorkflowRunne
|
|
|
27
27
|
export { resetDb, installTestIsolation } from "./testing";
|
|
28
28
|
export { slugifyName, availableSlug } from "./slugify";
|
|
29
29
|
export type { SsrResponse, SsrCookieOptions, SsrMetadata, Sitemap, SitemapEntry, Robots, RobotsRule, } from "./ssr-runtime";
|
|
30
|
-
export type { QueryCtx, MutationCtx, ActionCtx, DbReader, DbWriter, Stream, Scheduler, AuthInfo, AuthMode, AuthRequirement, FnDefinition, Validator, AnyValidator, ValidatorSchema, InferValidator, InferArgs, RequireMember, RequireMemberOptions, Shards, ShardsReader, ShardsWriter, ShardInfo, ShardTransfer, MemberRow, Workflows, WorkflowRunSummary, WorkflowRunStatus, Audit, AuditLog, AuditEntry, Agents, AgentRunOptions, VectorSearchQuery, VectorSearchResult, SearchResult, PaginationResult, Llm, LlmMessage, LlmContentBlock, LlmTool, LlmCompleteRequest, LlmCompleteResponse, LlmStreamEvent, Rooms, Domains, TenantDomainResult, TenantDomainRecord, TenantDomainDns, DomainAvailability, DomainContact, RegisterDomainOptions, RegisteredDomainResult, } from "./types";
|
|
30
|
+
export type { QueryCtx, MutationCtx, ActionCtx, DbReader, DbWriter, Stream, Scheduler, AuthInfo, AuthMode, AuthRequirement, FnDefinition, Validator, AnyValidator, ValidatorSchema, InferValidator, InferArgs, RequireMember, RequireMemberOptions, Shards, ShardsReader, ShardsWriter, ShardInfo, ShardTransfer, MemberRow, Workflows, WorkflowRunSummary, WorkflowRunStatus, Audit, AuditLog, AuditEntry, Agents, AgentRunOptions, VectorSearchQuery, VectorSearchResult, SearchResult, PaginationResult, Llm, LlmMessage, LlmContentBlock, LlmTool, LlmCompleteRequest, LlmCompleteResponse, LlmStreamEvent, Rooms, Domains, TenantDomainResult, TenantDomainRecord, TenantDomainDns, DomainAvailability, DomainContact, RegisterDomainOptions, RegisteredDomainResult, Files, ActionFiles, StoreFileOptions, StoredFile, } from "./types";
|
package/dist/types.d.ts
CHANGED
|
@@ -890,6 +890,44 @@ export interface Files {
|
|
|
890
890
|
ttlSecs?: number;
|
|
891
891
|
}): Promise<string>;
|
|
892
892
|
}
|
|
893
|
+
/** Options for {@link ActionFiles.store}. */
|
|
894
|
+
export interface StoreFileOptions {
|
|
895
|
+
/** File name, 1-255 characters, no path separators. */
|
|
896
|
+
name: string;
|
|
897
|
+
/** Defaults to `application/octet-stream`. */
|
|
898
|
+
contentType?: string;
|
|
899
|
+
/** Readable by anyone, signed in or not. Defaults to false. */
|
|
900
|
+
public?: boolean;
|
|
901
|
+
}
|
|
902
|
+
/** A file written by {@link ActionFiles.store}. */
|
|
903
|
+
export interface StoredFile {
|
|
904
|
+
id: string;
|
|
905
|
+
/** Where the file is served: `/api/files/<id>` or the storage CDN URL. */
|
|
906
|
+
url: string;
|
|
907
|
+
size: number;
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* `ctx.files` in an action: the read-side {@link Files} plus writes to the
|
|
911
|
+
* app's file storage (the backend `/api/files` uses). Writes run only in
|
|
912
|
+
* actions: a stored or deleted file cannot roll back with a query or
|
|
913
|
+
* mutation.
|
|
914
|
+
*
|
|
915
|
+
* A stored file is owned by the calling user and tenant, as if that user
|
|
916
|
+
* had uploaded it. With no user (a scheduled job, a public webhook) the
|
|
917
|
+
* file is system-owned: readable through {@link Files.signedUrl}, by an
|
|
918
|
+
* unscoped admin, or by anyone when `public` is set.
|
|
919
|
+
*/
|
|
920
|
+
export interface ActionFiles extends Files {
|
|
921
|
+
/**
|
|
922
|
+
* Store bytes as a new file. At most 25 MiB, or `PYLON_MAX_UPLOAD_BYTES`
|
|
923
|
+
* when that is lower.
|
|
924
|
+
*/
|
|
925
|
+
store(data: Uint8Array | ArrayBuffer | string, opts: StoreFileOptions): Promise<StoredFile>;
|
|
926
|
+
/** Delete a stored file. `deleted` is false when it did not exist. */
|
|
927
|
+
delete(fileId: string): Promise<{
|
|
928
|
+
deleted: boolean;
|
|
929
|
+
}>;
|
|
930
|
+
}
|
|
893
931
|
/**
|
|
894
932
|
* Shard tickets: short-lived, signed permission to join one realtime shard,
|
|
895
933
|
* with claims the shard's authorization hooks read without a database
|
|
@@ -1312,7 +1350,7 @@ export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
|
1312
1350
|
/** Environment variables / secrets. */
|
|
1313
1351
|
env: Record<string, string>;
|
|
1314
1352
|
/** Signed file-download URLs — see {@link Files}. */
|
|
1315
|
-
files:
|
|
1353
|
+
files: ActionFiles;
|
|
1316
1354
|
/** Shard tickets, reads, and start/stop — see {@link Shards}. */
|
|
1317
1355
|
shards: Shards;
|
|
1318
1356
|
/** Run a registered query within its own read transaction. */
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
package/src/runtime.ts
CHANGED
|
@@ -22,6 +22,8 @@ import type {
|
|
|
22
22
|
EmailOptions,
|
|
23
23
|
EmailSender,
|
|
24
24
|
Files,
|
|
25
|
+
ActionFiles,
|
|
26
|
+
StoredFile,
|
|
25
27
|
Shards,
|
|
26
28
|
ShardInfo,
|
|
27
29
|
ShardTransfer,
|
|
@@ -640,6 +642,56 @@ function buildFiles(callId: string): Files {
|
|
|
640
642
|
};
|
|
641
643
|
}
|
|
642
644
|
|
|
645
|
+
/** `ctx.files` in an action: {@link buildFiles} plus store and delete. */
|
|
646
|
+
function buildActionFiles(callId: string): ActionFiles {
|
|
647
|
+
return {
|
|
648
|
+
...buildFiles(callId),
|
|
649
|
+
async store(data, opts) {
|
|
650
|
+
const size =
|
|
651
|
+
typeof data === "string" ? new TextEncoder().encode(data).byteLength : data.byteLength;
|
|
652
|
+
// Refused here, before encoding: a larger message would exceed the
|
|
653
|
+
// runner's frame limit and never reach the host's check.
|
|
654
|
+
if (size > FILES_STORE_MAX_BYTES) {
|
|
655
|
+
const err = new Error(
|
|
656
|
+
`ctx.files.store accepts at most ${FILES_STORE_MAX_BYTES} bytes (got ${size})`,
|
|
657
|
+
);
|
|
658
|
+
(err as { code?: string }).code = "FILE_TOO_LARGE";
|
|
659
|
+
throw err;
|
|
660
|
+
}
|
|
661
|
+
return rpc(callId, {
|
|
662
|
+
type: "files_op",
|
|
663
|
+
op: "store",
|
|
664
|
+
name: opts.name,
|
|
665
|
+
content_type: opts.contentType ?? null,
|
|
666
|
+
public: opts.public ?? false,
|
|
667
|
+
data_base64: toBase64(data),
|
|
668
|
+
}) as Promise<StoredFile>;
|
|
669
|
+
},
|
|
670
|
+
async delete(fileId) {
|
|
671
|
+
return rpc(callId, {
|
|
672
|
+
type: "files_op",
|
|
673
|
+
op: "delete",
|
|
674
|
+
file_id: fileId,
|
|
675
|
+
}) as Promise<{ deleted: boolean }>;
|
|
676
|
+
},
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/** Largest `ctx.files.store` payload. Mirrors the host's
|
|
681
|
+
* FILES_STORE_MAX_BYTES; `PYLON_MAX_UPLOAD_BYTES` can lower the host's. */
|
|
682
|
+
const FILES_STORE_MAX_BYTES = 25 * 1024 * 1024;
|
|
683
|
+
|
|
684
|
+
/** Base64 of bytes, or of a string's UTF-8 encoding. */
|
|
685
|
+
function toBase64(data: Uint8Array | ArrayBuffer | string): string {
|
|
686
|
+
const bytes =
|
|
687
|
+
typeof data === "string"
|
|
688
|
+
? new TextEncoder().encode(data)
|
|
689
|
+
: data instanceof ArrayBuffer
|
|
690
|
+
? new Uint8Array(data)
|
|
691
|
+
: data;
|
|
692
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
693
|
+
}
|
|
694
|
+
|
|
643
695
|
export function buildSsrFnCaller(
|
|
644
696
|
callId: string,
|
|
645
697
|
): (name: string, args?: Record<string, unknown>) => Promise<unknown> {
|
|
@@ -1340,7 +1392,7 @@ function buildActionCtx(
|
|
|
1340
1392
|
(err as any).code = code;
|
|
1341
1393
|
return err;
|
|
1342
1394
|
},
|
|
1343
|
-
files:
|
|
1395
|
+
files: buildActionFiles(callId),
|
|
1344
1396
|
shards: buildShards(callId),
|
|
1345
1397
|
// Actions have no ctx.db; read membership via the built-in internal query.
|
|
1346
1398
|
requireMember: makeRequireMember(auth.userId, (entity, filter) =>
|
|
@@ -1532,7 +1584,10 @@ async function handleCall(msg: CallMessage): Promise<void> {
|
|
|
1532
1584
|
requireMember: makeRequireMember(auth.userId, (entity, filter) =>
|
|
1533
1585
|
reader.query(entity, { ...filter, $limit: 1 }),
|
|
1534
1586
|
),
|
|
1535
|
-
|
|
1587
|
+
// Typed as read-only `Files`; `store`/`delete` still exist at runtime
|
|
1588
|
+
// so a call from a query or mutation gets the host's
|
|
1589
|
+
// FILES_WRITE_NOT_ALLOWED instead of a TypeError.
|
|
1590
|
+
files: buildActionFiles(msg.call_id),
|
|
1536
1591
|
shards: buildShards(msg.call_id),
|
|
1537
1592
|
};
|
|
1538
1593
|
break;
|
|
@@ -1558,7 +1613,10 @@ async function handleCall(msg: CallMessage): Promise<void> {
|
|
|
1558
1613
|
requireMember: makeRequireMember(auth.userId, (entity, filter) =>
|
|
1559
1614
|
writer.query(entity, { ...filter, $limit: 1 }),
|
|
1560
1615
|
),
|
|
1561
|
-
|
|
1616
|
+
// Typed as read-only `Files`; `store`/`delete` still exist at runtime
|
|
1617
|
+
// so a call from a query or mutation gets the host's
|
|
1618
|
+
// FILES_WRITE_NOT_ALLOWED instead of a TypeError.
|
|
1619
|
+
files: buildActionFiles(msg.call_id),
|
|
1562
1620
|
shards: buildShards(msg.call_id),
|
|
1563
1621
|
};
|
|
1564
1622
|
break;
|
package/src/types.ts
CHANGED
|
@@ -992,6 +992,48 @@ export interface Files {
|
|
|
992
992
|
signedUrl(fileId: string, opts?: { ttlSecs?: number }): Promise<string>;
|
|
993
993
|
}
|
|
994
994
|
|
|
995
|
+
/** Options for {@link ActionFiles.store}. */
|
|
996
|
+
export interface StoreFileOptions {
|
|
997
|
+
/** File name, 1-255 characters, no path separators. */
|
|
998
|
+
name: string;
|
|
999
|
+
/** Defaults to `application/octet-stream`. */
|
|
1000
|
+
contentType?: string;
|
|
1001
|
+
/** Readable by anyone, signed in or not. Defaults to false. */
|
|
1002
|
+
public?: boolean;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/** A file written by {@link ActionFiles.store}. */
|
|
1006
|
+
export interface StoredFile {
|
|
1007
|
+
id: string;
|
|
1008
|
+
/** Where the file is served: `/api/files/<id>` or the storage CDN URL. */
|
|
1009
|
+
url: string;
|
|
1010
|
+
size: number;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/**
|
|
1014
|
+
* `ctx.files` in an action: the read-side {@link Files} plus writes to the
|
|
1015
|
+
* app's file storage (the backend `/api/files` uses). Writes run only in
|
|
1016
|
+
* actions: a stored or deleted file cannot roll back with a query or
|
|
1017
|
+
* mutation.
|
|
1018
|
+
*
|
|
1019
|
+
* A stored file is owned by the calling user and tenant, as if that user
|
|
1020
|
+
* had uploaded it. With no user (a scheduled job, a public webhook) the
|
|
1021
|
+
* file is system-owned: readable through {@link Files.signedUrl}, by an
|
|
1022
|
+
* unscoped admin, or by anyone when `public` is set.
|
|
1023
|
+
*/
|
|
1024
|
+
export interface ActionFiles extends Files {
|
|
1025
|
+
/**
|
|
1026
|
+
* Store bytes as a new file. At most 25 MiB, or `PYLON_MAX_UPLOAD_BYTES`
|
|
1027
|
+
* when that is lower.
|
|
1028
|
+
*/
|
|
1029
|
+
store(
|
|
1030
|
+
data: Uint8Array | ArrayBuffer | string,
|
|
1031
|
+
opts: StoreFileOptions,
|
|
1032
|
+
): Promise<StoredFile>;
|
|
1033
|
+
/** Delete a stored file. `deleted` is false when it did not exist. */
|
|
1034
|
+
delete(fileId: string): Promise<{ deleted: boolean }>;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
995
1037
|
/**
|
|
996
1038
|
* Shard tickets: short-lived, signed permission to join one realtime shard,
|
|
997
1039
|
* with claims the shard's authorization hooks read without a database
|
|
@@ -1436,7 +1478,7 @@ export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
|
1436
1478
|
/** Environment variables / secrets. */
|
|
1437
1479
|
env: Record<string, string>;
|
|
1438
1480
|
/** Signed file-download URLs — see {@link Files}. */
|
|
1439
|
-
files:
|
|
1481
|
+
files: ActionFiles;
|
|
1440
1482
|
/** Shard tickets, reads, and start/stop — see {@link Shards}. */
|
|
1441
1483
|
shards: Shards;
|
|
1442
1484
|
/** Run a registered query within its own read transaction. */
|