@neondatabase/functions 0.3.0 → 0.5.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/README.md +7 -19
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lib/wait-until.d.ts +13 -26
- package/dist/lib/wait-until.d.ts.map +1 -1
- package/dist/lib/wait-until.js +2 -54
- package/dist/lib/wait-until.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,25 +27,13 @@ export default {
|
|
|
27
27
|
`waitUntil(promise)` forwards the promise to the Neon Functions runtime, which keeps
|
|
28
28
|
the invocation alive until the promise settles (up to the 15-minute `waitUntil` limit).
|
|
29
29
|
When no invocation context is in scope — local dev, tests, or any non-Neon host — it is
|
|
30
|
-
a **no-op**: the promise is accepted and ignored
|
|
31
|
-
without branching. Passing a
|
|
30
|
+
a **no-op**: the promise is accepted and ignored (it still runs on its own, it just
|
|
31
|
+
isn't tracked), so the same code runs everywhere without branching. Passing a
|
|
32
|
+
non-`Promise` throws a `TypeError`.
|
|
32
33
|
|
|
33
34
|
## Runtime integration
|
|
34
35
|
|
|
35
|
-
The runtime
|
|
36
|
-
|
|
37
|
-
`
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
To make `waitUntil` resolve to a given invocation, wrap the handler with
|
|
41
|
-
`runWithRequestContext`. This is intended for the Neon Functions runtime; application
|
|
42
|
-
code should not need it.
|
|
43
|
-
|
|
44
|
-
```ts
|
|
45
|
-
import { runWithRequestContext } from "@neondatabase/functions";
|
|
46
|
-
|
|
47
|
-
runWithRequestContext({ waitUntil: realWaitUntil }, () => handler(req));
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Because the context lives in `AsyncLocalStorage`, concurrent invocations in the same
|
|
51
|
-
isolate each see their own context and never clobber one another.
|
|
36
|
+
The runtime publishes the active invocation context on `globalThis.NEON_REQUEST_CONTEXT`
|
|
37
|
+
as a getter that returns the live context object directly — `{ waitUntil }` during an
|
|
38
|
+
invocation, `undefined` outside one. `waitUntil` reads that value straight off the
|
|
39
|
+
global, so there is nothing for application code to wire up.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { waitUntil } from "./lib/wait-until.js";
|
|
2
|
+
export { waitUntil };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { waitUntil } from "./lib/wait-until.js";
|
|
2
|
+
export { waitUntil };
|
package/dist/lib/wait-until.d.ts
CHANGED
|
@@ -1,33 +1,20 @@
|
|
|
1
1
|
//#region src/lib/wait-until.d.ts
|
|
2
|
-
type WaitUntil = (promise: Promise<unknown>) => void;
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*/
|
|
7
|
-
type NeonFunctionsContext = {
|
|
8
|
-
waitUntil?: WaitUntil;
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Well-known `globalThis` symbol under which the per-invocation context provider is
|
|
12
|
-
* published. Mirrors the convention used by Vercel and Next.js.
|
|
13
|
-
*/
|
|
14
|
-
declare const NEON_FUNCTIONS_CONTEXT: unique symbol;
|
|
15
|
-
/**
|
|
16
|
-
* Defers async work past the response by forwarding the promise to the Neon Functions
|
|
17
|
-
* runtime, which keeps the invocation alive until the promise settles.
|
|
3
|
+
* `waitUntil(promise)` defers async work past a Neon Function's response: the runtime
|
|
4
|
+
* keeps the invocation alive until the promise settles (up to the 15-minute limit).
|
|
18
5
|
*
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
21
|
-
*
|
|
6
|
+
* The runtime publishes the active invocation context on `globalThis.NEON_REQUEST_CONTEXT`
|
|
7
|
+
* (a getter returning `{ waitUntil }` during an invocation, `undefined` outside one), so we
|
|
8
|
+
* read it directly. Off-platform — local dev, tests, non-Neon hosts — there is no context
|
|
9
|
+
* and this is a no-op, mirroring `@vercel/functions`: the promise the caller created still
|
|
10
|
+
* runs on its own, it just isn't tracked. Passing a non-Promise throws a `TypeError`.
|
|
22
11
|
*/
|
|
12
|
+
declare global {
|
|
13
|
+
var NEON_REQUEST_CONTEXT: {
|
|
14
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
15
|
+
} | undefined;
|
|
16
|
+
}
|
|
23
17
|
declare function waitUntil(promise: Promise<unknown>): void;
|
|
24
|
-
/**
|
|
25
|
-
* Runtime entry point: binds `context` as the current invocation context for the
|
|
26
|
-
* duration of `fn` (and any async work it spawns), so calls to `waitUntil` inside it
|
|
27
|
-
* forward to `context.waitUntil`. Intended for the Neon Functions runtime to wrap each
|
|
28
|
-
* invocation; application code should not need this.
|
|
29
|
-
*/
|
|
30
|
-
declare function runWithRequestContext<T>(context: NeonFunctionsContext, fn: () => T): T;
|
|
31
18
|
//#endregion
|
|
32
|
-
export {
|
|
19
|
+
export { waitUntil };
|
|
33
20
|
//# sourceMappingURL=wait-until.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait-until.d.ts","names":[],"sources":["../../src/lib/wait-until.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"wait-until.d.ts","names":[],"sources":["../../src/lib/wait-until.ts"],"mappings":";;;;;;AAgBmC;AAanC;;;;;;0BAb4B;;;iBAaZ,SAAA,UAAmB"}
|
package/dist/lib/wait-until.js
CHANGED
|
@@ -1,64 +1,12 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
1
|
//#region src/lib/wait-until.ts
|
|
3
|
-
/**
|
|
4
|
-
* `waitUntil` extends the lifetime of a Neon Function invocation so background work
|
|
5
|
-
* (logging, cache writes, analytics, …) can finish after the response has been sent.
|
|
6
|
-
*
|
|
7
|
-
* The public API mirrors Vercel's `@vercel/functions`: import `waitUntil` and call it
|
|
8
|
-
* directly with a promise (`waitUntil(promise)`). Under the hood the per-invocation
|
|
9
|
-
* context is carried by an `AsyncLocalStorage`, so concurrent invocations sharing the
|
|
10
|
-
* same isolate never clobber each other's context.
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* Well-known `globalThis` symbol under which the per-invocation context provider is
|
|
14
|
-
* published. Mirrors the convention used by Vercel and Next.js.
|
|
15
|
-
*/
|
|
16
|
-
const NEON_FUNCTIONS_CONTEXT = Symbol.for("@neondatabase/functions/request-context");
|
|
17
|
-
/**
|
|
18
|
-
* Holds the per-invocation context. Each `runWithRequestContext(...)` call binds a
|
|
19
|
-
* fresh context for the duration of its callback (and any async work it spawns), so
|
|
20
|
-
* `waitUntil` always resolves to the right invocation even under concurrency.
|
|
21
|
-
*/
|
|
22
|
-
const requestContextStore = new AsyncLocalStorage();
|
|
23
|
-
const globalWithContext = globalThis;
|
|
24
|
-
/**
|
|
25
|
-
* Publish a stable provider whose `get()` reads the current store. Installed once;
|
|
26
|
-
* if another copy of this module (or the host runtime) has already published a
|
|
27
|
-
* provider, we leave it in place rather than clobber it.
|
|
28
|
-
*/
|
|
29
|
-
globalWithContext[NEON_FUNCTIONS_CONTEXT] ??= { get: () => requestContextStore.getStore() };
|
|
30
|
-
/**
|
|
31
|
-
* Reads the current invocation context off the `globalThis` provider, falling back to
|
|
32
|
-
* an empty context when no provider is published or no invocation is in scope.
|
|
33
|
-
*/
|
|
34
|
-
function getContext() {
|
|
35
|
-
return globalWithContext[NEON_FUNCTIONS_CONTEXT]?.get?.() ?? {};
|
|
36
|
-
}
|
|
37
2
|
function isPromise(value) {
|
|
38
3
|
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
39
4
|
}
|
|
40
|
-
/**
|
|
41
|
-
* Defers async work past the response by forwarding the promise to the Neon Functions
|
|
42
|
-
* runtime, which keeps the invocation alive until the promise settles.
|
|
43
|
-
*
|
|
44
|
-
* The context is resolved at call time from the enclosing invocation, so this stays
|
|
45
|
-
* correct under concurrency. When no invocation context is in scope (local dev, tests,
|
|
46
|
-
* non-Neon hosts), this is a no-op: the promise is accepted and ignored.
|
|
47
|
-
*/
|
|
48
5
|
function waitUntil(promise) {
|
|
49
6
|
if (!isPromise(promise)) throw new TypeError(`waitUntil can only be called with a Promise, got ${typeof promise}`);
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Runtime entry point: binds `context` as the current invocation context for the
|
|
54
|
-
* duration of `fn` (and any async work it spawns), so calls to `waitUntil` inside it
|
|
55
|
-
* forward to `context.waitUntil`. Intended for the Neon Functions runtime to wrap each
|
|
56
|
-
* invocation; application code should not need this.
|
|
57
|
-
*/
|
|
58
|
-
function runWithRequestContext(context, fn) {
|
|
59
|
-
return requestContextStore.run(context, fn);
|
|
7
|
+
globalThis.NEON_REQUEST_CONTEXT?.waitUntil?.(promise);
|
|
60
8
|
}
|
|
61
9
|
//#endregion
|
|
62
|
-
export {
|
|
10
|
+
export { waitUntil };
|
|
63
11
|
|
|
64
12
|
//# sourceMappingURL=wait-until.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wait-until.js","names":[],"sources":["../../src/lib/wait-until.ts"],"sourcesContent":["/**\n * `waitUntil`
|
|
1
|
+
{"version":3,"file":"wait-until.js","names":[],"sources":["../../src/lib/wait-until.ts"],"sourcesContent":["/**\n * `waitUntil(promise)` defers async work past a Neon Function's response: the runtime\n * keeps the invocation alive until the promise settles (up to the 15-minute limit).\n *\n * The runtime publishes the active invocation context on `globalThis.NEON_REQUEST_CONTEXT`\n * (a getter returning `{ waitUntil }` during an invocation, `undefined` outside one), so we\n * read it directly. Off-platform — local dev, tests, non-Neon hosts — there is no context\n * and this is a no-op, mirroring `@vercel/functions`: the promise the caller created still\n * runs on its own, it just isn't tracked. Passing a non-Promise throws a `TypeError`.\n */\n\ndeclare global {\n\t// Published by the Neon Functions runtime. Declared here (the only way to type an\n\t// augmented global) so it can be read off `globalThis` without a cast. `var` is the\n\t// required form for a global augmentation.\n\tvar NEON_REQUEST_CONTEXT:\n\t\t| { waitUntil?: (promise: Promise<unknown>) => void }\n\t\t| undefined;\n}\n\nfunction isPromise(value: unknown): value is Promise<unknown> {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"then\" in value &&\n\t\ttypeof value.then === \"function\"\n\t);\n}\n\nexport function waitUntil(promise: Promise<unknown>): void {\n\tif (!isPromise(promise)) {\n\t\tthrow new TypeError(\n\t\t\t`waitUntil can only be called with a Promise, got ${typeof promise}`,\n\t\t);\n\t}\n\tglobalThis.NEON_REQUEST_CONTEXT?.waitUntil?.(promise);\n}\n"],"mappings":";AAoBA,SAAS,UAAU,OAA2C;CAC7D,OACC,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAO,MAAM,SAAS;AAExB;AAEA,SAAgB,UAAU,SAAiC;CAC1D,IAAI,CAAC,UAAU,OAAO,GACrB,MAAM,IAAI,UACT,oDAAoD,OAAO,SAC5D;CAED,WAAW,sBAAsB,YAAY,OAAO;AACrD"}
|
package/package.json
CHANGED