@run402/functions 2.4.1 → 2.6.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 +107 -0
- package/dist/auth.d.ts +47 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +92 -4
- package/dist/auth.js.map +1 -1
- package/dist/cache.d.ts +122 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +243 -0
- package/dist/cache.js.map +1 -0
- package/dist/db.d.ts +26 -7
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +38 -8
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/jwt.d.ts +55 -0
- package/dist/lib/jwt.d.ts.map +1 -0
- package/dist/lib/jwt.js +196 -0
- package/dist/lib/jwt.js.map +1 -0
- package/dist/runtime-context.d.ts +152 -0
- package/dist/runtime-context.d.ts.map +1 -0
- package/dist/runtime-context.js +170 -0
- package/dist/runtime-context.js.map +1 -0
- package/package.json +2 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-context.d.ts","sourceRoot":"","sources":["../src/runtime-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;oCACoC;AACpC,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB;yBACqB;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;qDACiD;IACjD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;yDACqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb;;;uBAGmB;IACnB,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;KACxD,CAAC;IACF;;;oBAGgB;IAChB,kBAAkB,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IACvC;;;8CAG0C;IAC1C,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;CAC5B;AAED;oEACoE;AACpE,eAAO,MAAM,GAAG,sCAA6C,CAAC;AAE9D;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,iBAAiB,GAAG,SAAS,CAEjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,oBAAoB,GAAG,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,oBAAoB,GAAG,QAAQ,CAAC,CAAC,EACrI,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAC7B,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAOhB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,QAAQ,CAAC,IAAI,sCAAsC;IACnD,QAAQ,CAAC,IAAI,gEAAgE;IAC7E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,kBAAkB,CAAC;gBAEtC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,kBAAkB;CAc1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,iBAAiB,CAS3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAUjD,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,OAAO,EAAE,EAAE,OAAO,EAC/D,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GAChC,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAe7B"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR request context primitive — capability `functions-sdk-auth-model`.
|
|
3
|
+
*
|
|
4
|
+
* The SSR Lambda runtime establishes this context via `als.run(...)`
|
|
5
|
+
* BEFORE importing or executing the Astro server bundle (or any other
|
|
6
|
+
* user-supplied code). SDK functions that need request-scoped state
|
|
7
|
+
* (`db()`, `getUser()`, `cache.*`, `assets.*`, `email.*`, `ai.*`) read
|
|
8
|
+
* from `getCurrentContext()` rather than requiring explicit context
|
|
9
|
+
* parameters at the call site.
|
|
10
|
+
*
|
|
11
|
+
* The `active` flag exists because Node's AsyncLocalStorage propagates
|
|
12
|
+
* into timers, microtasks, and unawaited promises created inside
|
|
13
|
+
* `als.run()`. Without an explicit flag, a `setTimeout(() => db()..., 60_000)`
|
|
14
|
+
* scheduled inside a handler would, when the timer fires later, still
|
|
15
|
+
* observe an `als.getStore()` pointing at the (now-completed) request —
|
|
16
|
+
* leading to stale or incorrect SDK behavior. The SSR runtime sets
|
|
17
|
+
* `active.value = false` IMMEDIATELY after the response body is fully
|
|
18
|
+
* materialized; SDK functions check the flag and throw
|
|
19
|
+
* `R402_SDK_OUTSIDE_REQUEST_CONTEXT` when it's false.
|
|
20
|
+
*
|
|
21
|
+
* Likewise `cacheBypassTainted.value` is set to `true` by `getUser()`
|
|
22
|
+
* and payment-primitive SDK calls during render; the SSR runtime returns
|
|
23
|
+
* its final value to the gateway in the Lambda response metadata envelope
|
|
24
|
+
* (NOT via in-process ALS — the gateway runs in a different process).
|
|
25
|
+
*
|
|
26
|
+
* @see openspec/changes/astro-ssr-runtime/specs/functions-sdk-auth-model/spec.md
|
|
27
|
+
* @see openspec/changes/astro-ssr-runtime/specs/routed-http-functions/spec.md
|
|
28
|
+
*/
|
|
29
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
30
|
+
/** The shared ALS instance. Modules in @run402/functions read from
|
|
31
|
+
* this; the SSR Lambda runtime (in @run402/astro) writes to it. */
|
|
32
|
+
export const als = new AsyncLocalStorage();
|
|
33
|
+
/**
|
|
34
|
+
* Read the current request context, or `undefined` if no SSR request
|
|
35
|
+
* is in flight. SDK functions check both this AND `active.value` to
|
|
36
|
+
* decide whether to honor the call.
|
|
37
|
+
*/
|
|
38
|
+
export function getCurrentContext() {
|
|
39
|
+
return als.getStore();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Establish a request context and run a callback inside it. The SSR
|
|
43
|
+
* Lambda runtime calls this exactly once per invocation, wrapping the
|
|
44
|
+
* full `App.render(request)` + body-materialization sequence.
|
|
45
|
+
*
|
|
46
|
+
* The `active` flag is set to `true` initially; the caller (the SSR
|
|
47
|
+
* runtime) flips it to `false` after the response body is materialized.
|
|
48
|
+
* Don't call this from user code — it's the runtime's primitive.
|
|
49
|
+
*/
|
|
50
|
+
export function runWithContext(context, callback) {
|
|
51
|
+
const full = {
|
|
52
|
+
...context,
|
|
53
|
+
cacheBypassTainted: context.cacheBypassTainted ?? { value: false },
|
|
54
|
+
active: context.active ?? { value: true },
|
|
55
|
+
};
|
|
56
|
+
return als.run(full, callback);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Throw a structured `R402_SDK_OUTSIDE_REQUEST_CONTEXT` error. Used by
|
|
60
|
+
* SDK functions when they're invoked with no ALS store OR while the
|
|
61
|
+
* context has been marked inactive.
|
|
62
|
+
*
|
|
63
|
+
* Per the api-error-envelope spec, the thrown error carries:
|
|
64
|
+
* - `code: 'R402_SDK_OUTSIDE_REQUEST_CONTEXT'`
|
|
65
|
+
* - `message`: names the SDK function and the cause
|
|
66
|
+
* - `suggestedFix`: recommends moving the call inside a handler OR
|
|
67
|
+
* not scheduling background work that outlives the response
|
|
68
|
+
* - `docs`: `https://docs.run402.com/sdk/errors#outside-request-context`
|
|
69
|
+
*/
|
|
70
|
+
export class Run402OutsideRequestContextError extends Error {
|
|
71
|
+
code = "R402_SDK_OUTSIDE_REQUEST_CONTEXT";
|
|
72
|
+
docs = "https://docs.run402.com/sdk/errors#outside-request-context";
|
|
73
|
+
suggestedFix;
|
|
74
|
+
sdkFunction;
|
|
75
|
+
cause;
|
|
76
|
+
constructor(sdkFunction, cause) {
|
|
77
|
+
const causeMsg = cause === "no_context"
|
|
78
|
+
? "no active request context (called from module scope or outside a handler)"
|
|
79
|
+
: "request context marked inactive (called from a timer or unawaited promise after response completion)";
|
|
80
|
+
super(`${sdkFunction}: ${causeMsg}`);
|
|
81
|
+
this.name = "Run402OutsideRequestContextError";
|
|
82
|
+
this.sdkFunction = sdkFunction;
|
|
83
|
+
this.cause = cause;
|
|
84
|
+
this.suggestedFix =
|
|
85
|
+
cause === "no_context"
|
|
86
|
+
? `Move the ${sdkFunction} call inside an HTTP request handler or Astro frontmatter. SDK functions cannot resolve project context outside an active request.`
|
|
87
|
+
: `The request that called ${sdkFunction} has already returned. Don't schedule SDK calls in setTimeout / setInterval / unawaited promises that outlive the handler.`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Assert that a request context is active. Returns the context on
|
|
92
|
+
* success; throws `Run402OutsideRequestContextError` on failure.
|
|
93
|
+
*
|
|
94
|
+
* SDK functions call this as the first line, e.g.:
|
|
95
|
+
*
|
|
96
|
+
* const ctx = requireActiveContext("db");
|
|
97
|
+
* // use ctx.projectId, ctx.request.headers, etc.
|
|
98
|
+
*/
|
|
99
|
+
export function requireActiveContext(sdkFunction) {
|
|
100
|
+
const ctx = als.getStore();
|
|
101
|
+
if (ctx === undefined) {
|
|
102
|
+
throw new Run402OutsideRequestContextError(sdkFunction, "no_context");
|
|
103
|
+
}
|
|
104
|
+
if (!ctx.active.value) {
|
|
105
|
+
throw new Run402OutsideRequestContextError(sdkFunction, "context_inactive");
|
|
106
|
+
}
|
|
107
|
+
return ctx;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Flip the cache-bypass taint flag on the current context. Called by
|
|
111
|
+
* `getUser()` and payment-primitive SDK calls to signal that the
|
|
112
|
+
* rendered response depends on request-scoped auth state and therefore
|
|
113
|
+
* MUST NOT be cached publicly.
|
|
114
|
+
*
|
|
115
|
+
* No-op if there is no active context (rather than throwing — the taint
|
|
116
|
+
* is moot when there's no cache layer to inform).
|
|
117
|
+
*/
|
|
118
|
+
export function taintCacheBypass() {
|
|
119
|
+
const ctx = als.getStore();
|
|
120
|
+
if (ctx !== undefined) {
|
|
121
|
+
ctx.cacheBypassTainted.value = true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Canonical registry of SDK functions that are "payment primitives" for
|
|
126
|
+
* cache-taint purposes. Calling any of these inside an active request
|
|
127
|
+
* context MUST flip `cacheBypassTainted.value = true`. The set is
|
|
128
|
+
* defined here so the spec, runtime, and docs share one source of truth.
|
|
129
|
+
*
|
|
130
|
+
* To add a new payment primitive: append to this set AND ensure the
|
|
131
|
+
* function's implementation calls `taintCacheBypass()` on every entry.
|
|
132
|
+
*
|
|
133
|
+
* @see openspec/changes/astro-ssr-runtime/specs/functions-sdk-auth-model/spec.md
|
|
134
|
+
*/
|
|
135
|
+
export const PAYMENT_PRIMITIVES = new Set([
|
|
136
|
+
// None implemented yet — the registry exists so the contract is
|
|
137
|
+
// explicit and discoverable. Payment-primitive SDK functions added
|
|
138
|
+
// in future changes (per Run402 x402/MPP roadmap) will register here
|
|
139
|
+
// as they land.
|
|
140
|
+
// Example future entries (commented to keep the set actually empty
|
|
141
|
+
// until the helpers ship):
|
|
142
|
+
// "payments.require",
|
|
143
|
+
// "payments.gate",
|
|
144
|
+
// "payments.fulfill",
|
|
145
|
+
]);
|
|
146
|
+
/**
|
|
147
|
+
* Helper for payment-primitive implementations. Wraps the body in a
|
|
148
|
+
* taint-on-entry call so the registry contract is enforced at the
|
|
149
|
+
* SDK layer rather than relying on each implementation to remember.
|
|
150
|
+
*
|
|
151
|
+
* Example:
|
|
152
|
+
* export const requirePayment = withPaymentTaint("payments.require", async (opts) => {
|
|
153
|
+
* // ... actual implementation
|
|
154
|
+
* });
|
|
155
|
+
*/
|
|
156
|
+
export function withPaymentTaint(name, impl) {
|
|
157
|
+
if (!PAYMENT_PRIMITIVES.has(name)) {
|
|
158
|
+
// Doesn't throw — adding a new primitive is a code change and the
|
|
159
|
+
// dev sees this on first invocation. Throwing would block legitimate
|
|
160
|
+
// experimentation. But emit a warning so the registry stays correct.
|
|
161
|
+
// eslint-disable-next-line no-console
|
|
162
|
+
console.warn(`[run402] withPaymentTaint("${name}") called but "${name}" is not in PAYMENT_PRIMITIVES. ` +
|
|
163
|
+
`Add it to packages/functions/src/runtime-context.ts to keep the cache-taint registry consistent.`);
|
|
164
|
+
}
|
|
165
|
+
return (...args) => {
|
|
166
|
+
taintCacheBypass();
|
|
167
|
+
return impl(...args);
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=runtime-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-context.js","sourceRoot":"","sources":["../src/runtime-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAuCrD;oEACoE;AACpE,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,iBAAiB,EAAqB,CAAC;AAE9D;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAqI,EACrI,QAA8B;IAE9B,MAAM,IAAI,GAAsB;QAC9B,GAAG,OAAO;QACV,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE;QAClE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;KAC1C,CAAC;IACF,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,gCAAiC,SAAQ,KAAK;IAChD,IAAI,GAAG,kCAAkC,CAAC;IAC1C,IAAI,GAAG,4DAA4D,CAAC;IACpE,YAAY,CAAS;IACrB,WAAW,CAAS;IACpB,KAAK,CAAoC;IAElD,YAAY,WAAmB,EAAE,KAAwC;QACvE,MAAM,QAAQ,GACZ,KAAK,KAAK,YAAY;YACpB,CAAC,CAAC,2EAA2E;YAC7E,CAAC,CAAC,sGAAsG,CAAC;QAC7G,KAAK,CAAC,GAAG,WAAW,KAAK,QAAQ,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,kCAAkC,CAAC;QAC/C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,YAAY;YACf,KAAK,KAAK,YAAY;gBACpB,CAAC,CAAC,YAAY,WAAW,oIAAoI;gBAC7J,CAAC,CAAC,2BAA2B,WAAW,4HAA4H,CAAC;IAC3K,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC3B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,gCAAgC,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,gCAAgC,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC3B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,GAAG,CAAC,kBAAkB,CAAC,KAAK,GAAG,IAAI,CAAC;IACtC,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC;AAC7D,gEAAgE;AAChE,mEAAmE;AACnE,qEAAqE;AACrE,gBAAgB;AAChB,mEAAmE;AACnE,2BAA2B;AAC3B,wBAAwB;AACxB,qBAAqB;AACrB,wBAAwB;CACzB,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,IAAiC;IAEjC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,kEAAkE;QAClE,qEAAqE;QACrE,qEAAqE;QACrE,sCAAsC;QACtC,OAAO,CAAC,IAAI,CACV,8BAA8B,IAAI,kBAAkB,IAAI,kCAAkC;YACxF,kGAAkG,CACrG,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,GAAG,IAAW,EAAW,EAAE;QACjC,gBAAgB,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IACvB,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@run402/functions",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "In-function helper library for Run402 serverless functions — db, adminDb, getUser, email, ai, assets. Auto-bundled into deployed functions; also installable for local TypeScript autocomplete.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,12 +23,7 @@
|
|
|
23
23
|
"engines": {
|
|
24
24
|
"node": ">=18"
|
|
25
25
|
},
|
|
26
|
-
"
|
|
27
|
-
"jsonwebtoken": "^9.0.2"
|
|
28
|
-
},
|
|
29
|
-
"devDependencies": {
|
|
30
|
-
"@types/jsonwebtoken": "^9.0.9"
|
|
31
|
-
},
|
|
26
|
+
"devDependencies": {},
|
|
32
27
|
"repository": {
|
|
33
28
|
"type": "git",
|
|
34
29
|
"url": "git+https://github.com/kychee-com/run402.git",
|