@pylonsync/functions 0.11.5 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-cli.d.ts +1 -0
- package/dist/build-compat.d.ts +81 -0
- package/dist/index.d.ts +1 -1
- package/dist/production-build.d.ts +47 -0
- package/dist/server-bundle.d.ts +31 -0
- package/dist/ssr-client-bundler.d.ts +39 -2
- package/dist/ssr-fonts.d.ts +1 -1
- package/dist/ssr-runtime.d.ts +13 -1
- package/dist/stdout-fence.d.ts +18 -0
- package/dist/types.d.ts +42 -0
- package/package.json +8 -4
- package/src/build-cli.ts +36 -0
- package/src/build-compat.test.ts +173 -0
- package/src/build-compat.ts +430 -0
- package/src/index.ts +1 -0
- package/src/production-build.test.ts +269 -0
- package/src/production-build.ts +577 -0
- package/src/runtime-shard-ticket.test.ts +87 -0
- package/src/runtime.ts +64 -82
- package/src/server-bundle.test.ts +89 -0
- package/src/server-bundle.ts +63 -0
- package/src/ssr-client-bundler.test.ts +51 -0
- package/src/ssr-client-bundler.ts +150 -21
- package/src/ssr-fonts.ts +1 -1
- package/src/ssr-og-runtime.ts +17 -5
- package/src/ssr-runtime.ts +112 -47
- package/src/stdout-fence.ts +69 -0
- package/src/types.ts +42 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Keeps stdout for the host protocol. See `fenceStdout`.
|
|
2
|
+
|
|
3
|
+
// Bun global used here. Declared locally so apps that type-check this source
|
|
4
|
+
// without bun-types still pass `tsc` (same pattern as runtime.ts).
|
|
5
|
+
declare const Bun: {
|
|
6
|
+
write(dest: unknown, data: string): unknown;
|
|
7
|
+
stderr: unknown;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Redirect console.* from user code to stderr so handlers can't accidentally
|
|
12
|
+
* emit a line that looks like a protocol frame and confuse the Rust reader.
|
|
13
|
+
*
|
|
14
|
+
* Before this guard, a handler calling `console.log('{"type":"return",...}')`
|
|
15
|
+
* — either intentionally or by logging an object shaped that way — would be
|
|
16
|
+
* parsed by the host as a real protocol message. Moving all console output
|
|
17
|
+
* to stderr keeps stdout reserved for NDJSON protocol frames only.
|
|
18
|
+
*
|
|
19
|
+
* The original console methods are saved on the console object as
|
|
20
|
+
* `__stdoutLog` etc. in case the runtime itself needs to write diagnostics
|
|
21
|
+
* to stdout for some reason (it currently doesn't).
|
|
22
|
+
*
|
|
23
|
+
* Safe to call more than once. A production server bundle calls it from its
|
|
24
|
+
* entry, before the app modules load, and the runtime's `main()` calls it
|
|
25
|
+
* again.
|
|
26
|
+
*/
|
|
27
|
+
export function fenceStdout(): void {
|
|
28
|
+
const c = globalThis.console as unknown as Record<string, unknown>;
|
|
29
|
+
if (c.__pylonFenced) return;
|
|
30
|
+
c.__pylonFenced = true;
|
|
31
|
+
const toStderr = (prefix: string) => (...args: unknown[]) => {
|
|
32
|
+
const line = args
|
|
33
|
+
.map((a) => {
|
|
34
|
+
if (typeof a === "string") return a;
|
|
35
|
+
// Error: JSON.stringify yields `{}` because message/stack are
|
|
36
|
+
// non-enumerable. That made `console.error("x:", err)` log as `x: {}`,
|
|
37
|
+
// hiding the real failure from operators. Unwrap by hand.
|
|
38
|
+
if (a instanceof Error) {
|
|
39
|
+
const parts = [a.stack || `${a.name}: ${a.message}`];
|
|
40
|
+
const code = (a as { code?: unknown }).code;
|
|
41
|
+
if (code !== undefined) parts.push(`code=${String(code)}`);
|
|
42
|
+
const cause = (a as { cause?: unknown }).cause;
|
|
43
|
+
if (cause !== undefined) {
|
|
44
|
+
try {
|
|
45
|
+
parts.push(`cause=${cause instanceof Error ? cause.stack || cause.message : JSON.stringify(cause)}`);
|
|
46
|
+
} catch {
|
|
47
|
+
parts.push(`cause=${String(cause)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return parts.join(" ");
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
return JSON.stringify(a);
|
|
54
|
+
} catch {
|
|
55
|
+
return String(a);
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
.join(" ");
|
|
59
|
+
Bun.write(Bun.stderr, `${prefix}${line}\n`);
|
|
60
|
+
};
|
|
61
|
+
// Intentional: we want console.* for user handlers to go to stderr.
|
|
62
|
+
// Overwrite the globals before any user code is loaded.
|
|
63
|
+
c.__stdoutLog = c.log;
|
|
64
|
+
c.log = toStderr("");
|
|
65
|
+
c.info = toStderr("");
|
|
66
|
+
c.warn = toStderr("[warn] ");
|
|
67
|
+
c.error = toStderr("[error] ");
|
|
68
|
+
c.debug = toStderr("[debug] ");
|
|
69
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -827,6 +827,42 @@ export interface Files {
|
|
|
827
827
|
signedUrl(fileId: string, opts?: { ttlSecs?: number }): Promise<string>;
|
|
828
828
|
}
|
|
829
829
|
|
|
830
|
+
/**
|
|
831
|
+
* Shard tickets: short-lived, signed permission to join one realtime shard,
|
|
832
|
+
* with claims the shard's authorization hooks read without a database
|
|
833
|
+
* call. Check what the user may do here, then mint:
|
|
834
|
+
*
|
|
835
|
+
* ```ts
|
|
836
|
+
* export default mutation({
|
|
837
|
+
* args: { characterId: v.id("Character") },
|
|
838
|
+
* async handler(ctx, args) {
|
|
839
|
+
* const c = await ctx.db.get("Character", args.characterId);
|
|
840
|
+
* if (c?.ownerId !== ctx.auth.userId) throw ctx.error("FORBIDDEN", "not your character");
|
|
841
|
+
* const shard = `zone-${c.zone}`;
|
|
842
|
+
* const ticket = await ctx.shards.ticket(shard, {
|
|
843
|
+
* subscriberId: c.id,
|
|
844
|
+
* claims: { character: c.id, realm: c.realm },
|
|
845
|
+
* });
|
|
846
|
+
* return { shard, ticket };
|
|
847
|
+
* },
|
|
848
|
+
* });
|
|
849
|
+
* ```
|
|
850
|
+
*
|
|
851
|
+
* The client passes the ticket when it connects (`connectShard(shard, {
|
|
852
|
+
* ticket })`). The shard rejects a ticket for another shard, another
|
|
853
|
+
* subscriber id, or past its expiry.
|
|
854
|
+
*/
|
|
855
|
+
export interface Shards {
|
|
856
|
+
/**
|
|
857
|
+
* Mint a ticket for `shardId`. `subscriberId` defaults to the calling
|
|
858
|
+
* user's id; `ttlSecs` defaults to 60 and is capped at 3600 by the host.
|
|
859
|
+
*/
|
|
860
|
+
ticket(
|
|
861
|
+
shardId: string,
|
|
862
|
+
opts?: { subscriberId?: string; claims?: Record<string, unknown>; ttlSecs?: number },
|
|
863
|
+
): Promise<string>;
|
|
864
|
+
}
|
|
865
|
+
|
|
830
866
|
/** Context for query handlers (read-only).
|
|
831
867
|
*
|
|
832
868
|
* NOTE: `ctx.llm` is NOT exposed here. Queries are reactive: a
|
|
@@ -852,6 +888,8 @@ export interface QueryCtx<R extends AuthRequirement = "optional"> {
|
|
|
852
888
|
requireMember: RequireMember;
|
|
853
889
|
/** Signed file-download URLs — see {@link Files}. */
|
|
854
890
|
files: Files;
|
|
891
|
+
/** Shard tickets — see {@link Shards}. */
|
|
892
|
+
shards: Shards;
|
|
855
893
|
/**
|
|
856
894
|
* Fires when the host cancels this call (idle timeout exceeded).
|
|
857
895
|
* Thread it into `fetch(url, { signal: ctx.signal })` or SDK calls so
|
|
@@ -880,6 +918,8 @@ export interface MutationCtx<R extends AuthRequirement = "optional"> {
|
|
|
880
918
|
workflows: Workflows;
|
|
881
919
|
/** Signed file-download URLs — see {@link Files}. */
|
|
882
920
|
files: Files;
|
|
921
|
+
/** Shard tickets — see {@link Shards}. */
|
|
922
|
+
shards: Shards;
|
|
883
923
|
/** Create a typed error that triggers rollback. */
|
|
884
924
|
error(code: string, message: string): Error;
|
|
885
925
|
/** Assert org membership (optionally a role) — see {@link RequireMember}. */
|
|
@@ -1053,6 +1093,8 @@ export interface ActionCtx<R extends AuthRequirement = "optional"> {
|
|
|
1053
1093
|
env: Record<string, string>;
|
|
1054
1094
|
/** Signed file-download URLs — see {@link Files}. */
|
|
1055
1095
|
files: Files;
|
|
1096
|
+
/** Shard tickets — see {@link Shards}. */
|
|
1097
|
+
shards: Shards;
|
|
1056
1098
|
/** Run a registered query within its own read transaction. */
|
|
1057
1099
|
runQuery<T = unknown>(
|
|
1058
1100
|
fnName: string,
|