@urbicon-ui/sveltekit-utils 8.8.0 → 8.10.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
@@ -46,6 +46,7 @@ Bind a typed, reactive value to a URL search param. When the value changes, the
46
46
 
47
47
  Low-level escape hatch if you prefer to update multiple params at once:
48
48
 
49
+ <!-- typecheck -->
49
50
  ```typescript
50
51
  import { updateUrlSearchParams } from '@urbicon-ui/sveltekit-utils/url.svelte';
51
52
 
@@ -90,14 +91,20 @@ Because the binding re-reads the URL rather than capturing it, the browser's bac
90
91
  The pure serializers work without SvelteKit — e.g. to parse the incoming query in a server `load` and fetch the first page during SSR. Use `searchParamsToViewSnapshot` from `./table-view`: it takes the *same* defaults object the component hands `createTableView`, so the server cannot resolve an absent param differently from the client, and it hands back the very shape a managed `source.query` receives.
91
92
 
92
93
  ```typescript
93
- // view-defaults.ts — imported by both the component and the load function
94
- export const userView = { pageSize: 25, sort: { column: 'joined', direction: 'desc' } };
94
+ // src/lib/view-defaults.ts — imported by the component and by the load function.
95
+ // `as const` keeps `direction` a `'desc'`, not a `string` the snapshot rejects.
96
+ export const userView = { pageSize: 25, sort: { column: 'joined', direction: 'desc' } } as const;
97
+ ```
95
98
 
96
- // +page.server.ts
99
+ <!-- typecheck -->
100
+ ```typescript
101
+ // src/routes/users/+page.server.ts
97
102
  import { searchParamsToViewSnapshot } from '@urbicon-ui/sveltekit-utils/table-view';
98
- import { userView } from './view-defaults';
103
+ import { fetchUsers } from '$lib/server/users';
104
+ import { userView } from '$lib/view-defaults';
105
+ import type { PageServerLoad } from './$types';
99
106
 
100
- export const load = async ({ url }) => ({
107
+ export const load: PageServerLoad = async ({ url }) => ({
101
108
  initialResult: await fetchUsers(searchParamsToViewSnapshot(url.searchParams, userView))
102
109
  });
103
110
  ```
@@ -116,13 +123,20 @@ The `./table-query` subpath that used to hold a second copy of this codec — sa
116
123
 
117
124
  Fire HTTP requests against SvelteKit server endpoints on an interval. Pair with a shared-secret header so endpoints can authenticate scheduled calls.
118
125
 
126
+ <!-- typecheck -->
119
127
  ```typescript
120
128
  // src/lib/server/cron.ts
121
129
  import { createCronRunner } from '@urbicon-ui/sveltekit-utils/cron';
122
130
  import { env } from '$env/dynamic/private';
123
131
 
132
+ // Runtime env, not `$env/static/private`: a node server reads its secret at
133
+ // start, not at build. The runner needs a `string`, so a missing one is a
134
+ // startup failure here — not an unauthenticated cron loop.
135
+ const secret = env.CRON_SECRET;
136
+ if (!secret) throw new Error('CRON_SECRET is not set');
137
+
124
138
  export const cron = createCronRunner({
125
- secret: env.CRON_SECRET,
139
+ secret,
126
140
  baseUrl: env.BASE_URL,
127
141
  jobs: [
128
142
  { path: '/api/cron/send-digest', intervalSeconds: 3600 },
@@ -136,12 +150,15 @@ cron.start();
136
150
 
137
151
  Receive the call and verify the secret inside your endpoint:
138
152
 
153
+ <!-- typecheck -->
139
154
  ```typescript
140
155
  // src/routes/api/cron/send-digest/+server.ts
141
156
  import { env } from '$env/dynamic/private';
157
+ import { sendDigest } from '$lib/server/digest';
158
+ import type { RequestHandler } from './$types';
142
159
 
143
- export const POST = async ({ request }) => {
144
- if (request.headers.get('x-cron-secret') !== env.CRON_SECRET) {
160
+ export const POST: RequestHandler = async ({ request }) => {
161
+ if (!env.CRON_SECRET || request.headers.get('x-cron-secret') !== env.CRON_SECRET) {
145
162
  return new Response('Forbidden', { status: 403 });
146
163
  }
147
164
  await sendDigest();
@@ -182,9 +199,13 @@ controller.abort();
182
199
 
183
200
  Emit the matching frames from the endpoint:
184
201
 
202
+ <!-- typecheck -->
185
203
  ```typescript
186
204
  // src/routes/api/chat/+server.ts
187
- export const POST = async ({ request }) => {
205
+ import { runModel } from '$lib/server/model';
206
+ import type { RequestHandler } from './$types';
207
+
208
+ export const POST: RequestHandler = async ({ request }) => {
188
209
  const stream = new ReadableStream({
189
210
  async start(controller) {
190
211
  const enc = new TextEncoder();
package/dist/cron.d.ts CHANGED
@@ -80,8 +80,12 @@ export interface CronRunner {
80
80
  * import { createCronRunner } from '@urbicon-ui/sveltekit-utils/cron';
81
81
  * import { env } from '$env/dynamic/private';
82
82
  *
83
+ * // runtime env: `secret` is a `string`, so a missing one fails at startup
84
+ * const secret = env.CRON_SECRET;
85
+ * if (!secret) throw new Error('CRON_SECRET is not set');
86
+ *
83
87
  * export const cron = createCronRunner({
84
- * secret: env.CRON_SECRET,
88
+ * secret,
85
89
  * baseUrl: env.BASE_URL,
86
90
  * jobs: [
87
91
  * { path: '/api/cron/send-digest', intervalSeconds: 3600 },
package/dist/cron.js CHANGED
@@ -16,8 +16,12 @@
16
16
  * import { createCronRunner } from '@urbicon-ui/sveltekit-utils/cron';
17
17
  * import { env } from '$env/dynamic/private';
18
18
  *
19
+ * // runtime env: `secret` is a `string`, so a missing one fails at startup
20
+ * const secret = env.CRON_SECRET;
21
+ * if (!secret) throw new Error('CRON_SECRET is not set');
22
+ *
19
23
  * export const cron = createCronRunner({
20
- * secret: env.CRON_SECRET,
24
+ * secret,
21
25
  * baseUrl: env.BASE_URL,
22
26
  * jobs: [
23
27
  * { path: '/api/cron/send-digest', intervalSeconds: 3600 },
@@ -115,7 +115,7 @@ export declare function searchParamsToViewPartial(sp: URLSearchParams, defaults:
115
115
  * @example
116
116
  * ```ts
117
117
  * // shared with the component that calls createTableView({ defaults })
118
- * export const invoiceView = { pageSize: 25, sort: { column: 'date', direction: 'desc' } };
118
+ * export const invoiceView = { pageSize: 25, sort: { column: 'date', direction: 'desc' } } as const;
119
119
  *
120
120
  * export const load = async ({ url }) => ({
121
121
  * initialResult: await fetchInvoices(searchParamsToViewSnapshot(url.searchParams, invoiceView))
@@ -155,7 +155,7 @@ export function searchParamsToViewPartial(sp, defaults, prefix = '') {
155
155
  * @example
156
156
  * ```ts
157
157
  * // shared with the component that calls createTableView({ defaults })
158
- * export const invoiceView = { pageSize: 25, sort: { column: 'date', direction: 'desc' } };
158
+ * export const invoiceView = { pageSize: 25, sort: { column: 'date', direction: 'desc' } } as const;
159
159
  *
160
160
  * export const load = async ({ url }) => ({
161
161
  * initialResult: await fetchInvoices(searchParamsToViewSnapshot(url.searchParams, invoiceView))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@urbicon-ui/sveltekit-utils",
3
- "version": "8.8.0",
3
+ "version": "8.10.0",
4
4
  "description": "SvelteKit helper utilities — createCronRunner, streamSse, and URL-state runes",
5
5
  "license": "MIT",
6
6
  "repository": {