@run402/functions 3.12.0 → 3.13.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 CHANGED
@@ -65,6 +65,10 @@ await adminDb()
65
65
  .order(col, { ascending? })
66
66
  .limit(n) / .offset(n)
67
67
 
68
+ // Terminal row modes (3.12.0+) — call last in the chain:
69
+ .single() // resolves the row OBJECT; 0 or >1 rows → R402DbError (status 406)
70
+ .maybeSingle() // resolves the row object or null; >1 rows → R402DbError (status 406)
71
+
68
72
  // Writes return arrays of affected rows.
69
73
  .insert(obj | obj[])
70
74
  .update(obj) // chain with .eq() to scope
@@ -74,6 +78,18 @@ await adminDb()
74
78
  .insert({ title: "x" }).select("id, title")
75
79
  ```
76
80
 
81
+ ```ts
82
+ // Fetch-one idiom — no more [row] destructuring or length checks:
83
+ const item = await db(req).from("items").select("*").eq("id", id).maybeSingle();
84
+ if (!item) return new Response("not found", { status: 404 });
85
+ ```
86
+
87
+ Row-count violations throw the same `R402DbError` as other builder failures
88
+ (`code: "R402_DB_QUERY_ERROR"`, `status: 406`, fingerprint-stable messages
89
+ like `PostgREST error (406): single() got 0 rows`) — branch on the
90
+ properties, not the message. Note the builder **throws** on errors; it never
91
+ returns a supabase-style `{ data, error }` envelope.
92
+
77
93
  ### `adminDb().sql(query, params?)` — raw SQL, always BYPASSRLS
78
94
 
79
95
  ```ts
@@ -229,7 +245,18 @@ await email.send({
229
245
  });
230
246
  ```
231
247
 
232
- Templates: `project_invite` (`project_name`, `invite_url`), `magic_link` (`project_name`, `link_url`, `expires_in`), `notification` (`project_name`, `message` ≤ 500 chars). Throws on rate limit, suppression, or no-mailbox.
248
+ Templates: `project_invite` (`project_name`, `invite_url`), `magic_link`
249
+ (`project_name`, `expires_in`, plus `link_url`, `code`, or both according to
250
+ the selected email-auth delivery mode), `notification` (`project_name`,
251
+ `message` ≤ 500 chars). For `magic_link`, at least one of `link_url` or `code`
252
+ is required; code-only rendering never synthesizes or exposes a link. Throws
253
+ on rate limit, suppression, or no-mailbox.
254
+
255
+ `auth.user()` preserves gateway authentication provenance in the open-ended
256
+ `Actor.amr` and `Actor.amrTimes` fields. An email-code session contains
257
+ `email_code` and its UNIX timestamp. It is an AAL1 email proof: it can satisfy
258
+ `auth.requireFresh({ maxAge: "10m", amr: ["email_code"] })`, but it never
259
+ satisfies a check for `amr: ["passkey"]`.
233
260
 
234
261
  ## `ai.translate` / `ai.moderate` / `ai.generateImage`
235
262
 
@@ -342,6 +369,8 @@ Read it back with `GET /projects/v1/:project_id/events?source=app` (or `run402 e
342
369
 
343
370
  **Errors.** Non-2xx responses throw `Run402EventsPlatformError` — see [Errors](#errors) below. In practice the two you're most likely to see are `code: "QUOTA_EXCEEDED"` (403, the organization's pooled daily quota is exhausted; `details: {resource: "events_per_day", scope, used, limit}`) and cross-project denials (`code: "FORBIDDEN"`, 403), alongside the two vocabulary errors above.
344
371
 
372
+ **Always `await` it (and every other side-channel call).** The function's sandbox freezes the moment your handler's response is returned — a fire-and-forget `void events.emit(...)` (or any un-awaited `fetch` to a webhook, analytics endpoint, etc.) is silently killed mid-flight and the event never lands. There is no error, no log, nothing: the request just evaporates with the freeze. If you don't want the caller's latency to include the emit, bound it instead of detaching it — `await` with a short `AbortSignal.timeout(...)` on hand-rolled calls — but never let the handler return before the side effect settles. (Observed in production 2026-07-25: an instrumentation emit that "worked in testing" recorded zero events until it was awaited.)
373
+
345
374
  ## Static-site generation (build-time use)
346
375
 
347
376
  The same library works at build time for static-site generation if you set `RUN402_SERVICE_KEY` and `RUN402_PROJECT_ID` in your `.env`:
@@ -31,8 +31,12 @@ export interface Actor {
31
31
  emailVerified: boolean;
32
32
  /** Last any-method auth proof, seconds-since-epoch. */
33
33
  authTime: number;
34
+ /** Authentication-method references such as `password`, `magic_link`,
35
+ * `email_code`, or `passkey`. This is intentionally open-ended. Email code
36
+ * is AAL1 and does not imply passkey freshness. */
34
37
  amr: string[];
35
- /** Per-AMR last-verified UNIX seconds. */
38
+ /** Per-AMR last-verified UNIX seconds, including `email_code` when that
39
+ * ceremony established or refreshed the session. */
36
40
  amrTimes: Record<string, number>;
37
41
  }
38
42
  /** Provider-shaped identity proof. The `wallet` shape carries an SIWX
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@run402/functions",
3
- "version": "3.12.0",
3
+ "version": "3.13.0",
4
4
  "description": "In-function helper library for Run402 serverless functions - db, adminDb, getUser, email, ai, assets, verifyWebhook. Auto-bundled into deployed functions; also installable for local TypeScript autocomplete.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",