@tollwyn/baukasten 1.3.3 → 2.0.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
@@ -7,11 +7,11 @@ A product builds its core and nothing of this.
7
7
 
8
8
  ## Set up a product
9
9
 
10
- A product is a SvelteKit 2 app with `@sveltejs/adapter-node` 5 and Svelte 5, tested with Playwright.
10
+ A product is a SvelteKit 3 app with `@sveltejs/adapter-node` 6 and Svelte 5, tested with Playwright.
11
11
 
12
12
  ```sh
13
13
  npm install --save-exact @tollwyn/baukasten@<version>
14
- npm install --save-dev @sveltejs/adapter-node@5 @playwright/test smtp-server
14
+ npm install --save-dev @sveltejs/adapter-node@6 @playwright/test smtp-server
15
15
  npx --no-install baukasten-stubs
16
16
  # fill in what the product owns (below)
17
17
  npx --no-install baukasten-check
@@ -42,9 +42,17 @@ them: `baukasten.config.ts`, `src/app.css`, `src/lib/server/baukasten.ts` and
42
42
  - `src/lib/server/handle.ts`: its own handle, after the baukasten's.
43
43
  - Its own pages. Their links to other pages go through `useLink` of `/ui`, else the referral tag
44
44
  `?via=` is lost on the way to the sign-up.
45
+ - `package.json`, whose `imports` map `"#lib/*"` to `"./src/lib/*"`, as `npx sv create` sets it
46
+ up: the stubs import `src/lib/server/` through it.
45
47
  - `vite.config.ts`, passing the options of the baukasten to SvelteKit:
46
48
  `sveltekit({ ...SVELTEKIT_OPTIONS, adapter: adapter() })`, with `SVELTEKIT_OPTIONS` from
47
- `@tollwyn/baukasten`. No page is prerendered.
49
+ `@tollwyn/baukasten`. No page is prerendered, and there is no `paths.origin`, which would build
50
+ one origin into the image.
51
+ - Its addresses, from `PUBLIC_ORIGIN` (`config.publicOrigin` of `kit.context()`), never from
52
+ `event.url`: adapter-node takes the origin of a request from its `host` header, with https, and
53
+ only `PUBLIC_ORIGIN` is the product's own.
54
+ - The redirect to Checkout: the address `kit.billing.checkout` gives is Stripe's, so the product
55
+ passes `{ external: true }` to `redirect`.
48
56
  - `migrations/`: its tables in the schema `public`, plain SQL, forward-only and expanding (the
49
57
  previous version must run against the new schema). Every table that holds data of an account
50
58
  points at it with `REFERENCES baukasten.accounts (id) ON DELETE CASCADE`. It reads the tables of
@@ -94,11 +102,11 @@ it. `muster/` shows all of it with Tailwind CSS 4, Skeleton and a font from font
94
102
 
95
103
  `baukasten-check` runs in the root of the product, before its gate, against the installed version:
96
104
  the stubs are there and unchanged, `deploy/auslieferung.json` names the webhook and the rights of
97
- the baukasten, SvelteKit and Svelte fit its peer ranges and adapter-node is version 5, `overrides`
98
- in `package.json` replaces nothing the baukasten depends on, no migration of the product names the
99
- schema `baukasten` beyond its references to `baukasten.accounts`, and the configuration and
100
- `SVELTEKIT_OPTIONS` are in place. Exit 0 when the product fits; else exit 1 with one line per
101
- problem.
105
+ the baukasten, SvelteKit and Svelte fit its peer ranges and adapter-node is version 6, `overrides`
106
+ in `package.json` replaces nothing the baukasten depends on and its `imports` map `#lib/*`, no
107
+ migration of the product names the schema `baukasten` beyond its references to
108
+ `baukasten.accounts`, and the configuration and `SVELTEKIT_OPTIONS` are in place. Exit 0 when the
109
+ product fits; else exit 1 with one line per problem.
102
110
 
103
111
  `e2e/baukasten.spec.ts` runs the connection test in the gate of the product, against the built
104
112
  product with the doubles of Stripe and mail: sign-up with a referral tag, mail and confirmation,
@@ -111,8 +119,8 @@ with `npx playwright test -g "the connection of the baukasten"`.
111
119
 
112
120
  A Shopify app built on this kit is a public app in the Shopify App Store, embedded in the admin of
113
121
  each store that installs it. Shopify installs it (managed installation) and bills it (Shopify App
114
- Pricing); the merchant never signs up or pays anywhere else. It is a SvelteKit 2 app with
115
- `@sveltejs/adapter-node` 5 and Svelte 5, tested with Playwright, like a web app, and on the same
122
+ Pricing); the merchant never signs up or pays anywhere else. It is a SvelteKit 3 app with
123
+ `@sveltejs/adapter-node` 6 and Svelte 5, tested with Playwright, like a web app, and on the same
116
124
  server; the accounts, Stripe and the legal pages of a web app are not part of it.
117
125
 
118
126
  What the baukasten brings for it: the installation with the token exchange and expiring offline
@@ -129,7 +137,7 @@ connection test among them.
129
137
 
130
138
  ```sh
131
139
  npm install --save-exact @tollwyn/baukasten@<version>
132
- npm install --save-dev @sveltejs/adapter-node@5 @playwright/test smtp-server
140
+ npm install --save-dev @sveltejs/adapter-node@6 @playwright/test smtp-server
133
141
  npx --no-install baukasten-stubs shopify
134
142
  # fill in what the app owns (below)
135
143
  npx --no-install baukasten-check
@@ -183,7 +191,8 @@ missing, it writes the files the app owns as a starting point: `baukasten.config
183
191
  - Runs: `periodic` with the work mark, as in a web app; a run asks the Admin API of a store with
184
192
  `kit.admin(domain)` and skips a store that is gone.
185
193
  - `vite.config.ts`: `sveltekit({ ...SHOPIFY_SVELTEKIT_OPTIONS, adapter: adapter() })`, with
186
- `SHOPIFY_SVELTEKIT_OPTIONS` from `@tollwyn/baukasten`. No page is prerendered.
194
+ `SHOPIFY_SVELTEKIT_OPTIONS` from `@tollwyn/baukasten`. No page is prerendered. The `imports` of
195
+ `package.json` and the addresses from `PUBLIC_ORIGIN` as in a web app.
187
196
  - `migrations/`: its tables in the schema `public`, forward-only and expanding. Every table that
188
197
  holds data of a store points at it with `REFERENCES baukasten.shops (domain) ON DELETE CASCADE`:
189
198
  so `shop/redact` deletes them with the store.
@@ -254,3 +263,55 @@ the baukasten do:
254
263
  - Loss and incidents: on a breach the operator stops the app through the delivery service, finds what
255
264
  was reached from the logs, and tells the stores concerned by email without undue delay, as the
256
265
  privacy text promises.
266
+
267
+ # From 1.x to 2.0
268
+
269
+ 2.0 moves the baukasten to SvelteKit 3 and adapter-node 6, and to version 23 of the SDK of Stripe.
270
+ Its pages, mails, legal texts, variables and migrations stay as they were: a product needs no new
271
+ variable, and its database stays as it is. A product on 1.x keeps running as it is; it takes 2.0 in
272
+ one change, a web app and a Shopify app alike:
273
+
274
+ 1. `npm install --save-exact @tollwyn/baukasten@<version>`, a version from 2.0.0 on, and
275
+ `npm install --save-dev @sveltejs/kit@3 @sveltejs/adapter-node@6`, with what SvelteKit 3 needs:
276
+ Vite 8, `@sveltejs/vite-plugin-svelte` 7, TypeScript 6 and Svelte from 5.57.1 on.
277
+ 2. The product's own code after the guide of SvelteKit,
278
+ https://svelte.dev/docs/kit/migrating-to-sveltekit-3 (`npx sv migrate sveltekit-3` does much of
279
+ it). What a product of the baukasten meets there:
280
+ - `$lib` becomes `#lib`, imported with the extension of the module (`#lib/texts.js`), and
281
+ `package.json` maps `"#lib/*": "./src/lib/*"` in `imports`.
282
+ - `tsconfig.json` extends `$app/tsconfig` and names its own `include`; a `types` of its own names
283
+ `$app/types` as well.
284
+ - `$app/environment` becomes `$app/env`, and `$app/stores` is gone (`$app/state`).
285
+ - The types of the hooks, `Handle` among them, come from `@sveltejs/kit/hooks`.
286
+ - `redirect` to another origin takes `{ external: true }`: the redirect to the address of
287
+ `kit.billing.checkout` too.
288
+ - `error(status, message)` takes the message as a string, further fields as a third argument.
289
+ 3. `npx --no-install baukasten-stubs` writes the stubs of 2.0, `npx --no-install baukasten-stubs
290
+ shopify` those of a Shopify app. The product's own `src/lib/server/handle.ts` takes `Handle`
291
+ from `@sveltejs/kit/hooks`.
292
+ 4. An override of `cookie` goes, where the product has one: SvelteKit 3 brings `cookie` 2, which
293
+ GHSA-pxg6-pf52-xh8x does not reach.
294
+ 5. `npx --no-install baukasten-check`, then the gate of the product.
295
+
296
+ What changes when it runs:
297
+
298
+ - adapter-node 6 reads no `ORIGIN`, and the server of the baukasten sets none: adapter-node takes
299
+ the origin of a request from its `host` header, with https. `PUBLIC_ORIGIN` stays the origin of
300
+ every address the baukasten makes and the one its check of unsafe requests compares with; the
301
+ product makes its own addresses from it, not from `event.url`, which says https on a local server
302
+ over http too.
303
+ - The `handleError` of the baukasten gets every error now, those of `error()` too: it leaves them as
304
+ they are, and logs the others as before.
305
+ - An enhanced form answers with the status of `fail()`, and one that posts to another page goes
306
+ there, as without JavaScript.
307
+ - adapter-node 6 bundles the baukasten into `build/`, as a library of Svelte, and its dependencies
308
+ with it. The image still carries the production `node_modules`: `server.js` and the migration
309
+ load the baukasten from there.
310
+ - adapter-node 6 serves the files of the build only, and only to `GET` and `HEAD`.
311
+ - Stripe answers the baukasten in its API version `2026-09-30.endive`; the payload of a webhook
312
+ keeps the version of its endpoint, as before.
313
+
314
+ What changes in the package: `@sveltejs/kit` is a peer from 3.1.0 on, and `baukasten-check` wants
315
+ adapter-node 6 and the `imports` of `#lib`. `init`, `handle` and `handleError` of `Kit` and
316
+ `ShopifyKit` take the types of SvelteKit 3. `SVELTEKIT_OPTIONS` and `SHOPIFY_SVELTEKIT_OPTIONS` hold
317
+ the same options as before, typed against `Config` of `@sveltejs/kit/vite`.
package/dist/check.js CHANGED
@@ -34,14 +34,19 @@ const SHOPIFY_ANGABE = z.looseObject({
34
34
  /** Words the review of the App Store refuses in an address of an app. */
35
35
  const REFUSED_IN_ADDRESS = ['shopify', 'example'];
36
36
  const ART = z.looseObject({ art: z.literal('shopify') });
37
- const PACKAGE = z.looseObject({ overrides: z.record(z.string(), z.unknown()).optional() });
37
+ const PACKAGE = z.looseObject({
38
+ overrides: z.record(z.string(), z.unknown()).optional(),
39
+ imports: z.record(z.string(), z.unknown()).optional()
40
+ });
41
+ /** The alias the stubs import the product's src/lib by, as SvelteKit sets it up. */
42
+ const LIB_IMPORT = { key: '#lib/*', target: './src/lib/*' };
38
43
  const PEER = z.looseObject({ version: z.string() });
39
44
  /**
40
- * What the product builds with, checked like a peer: adapter-node 6 no longer reads ORIGIN, which the
41
- * server of the baukasten sets from PUBLIC_ORIGIN. It is no peer, since only the build needs it, and
42
- * npm keeps a peer of a dependency in the image.
45
+ * What the product builds with, checked like a peer: adapter-node 5 cannot build SvelteKit 3, and the
46
+ * handler the stub server.js wraps, with its event at shutdown, is that of one major. It is no peer,
47
+ * since only the build needs it, and npm keeps a peer of a dependency in the image.
43
48
  */
44
- const BUILT_WITH = { '@sveltejs/adapter-node': '^5.0.0' };
49
+ const BUILT_WITH = { '@sveltejs/adapter-node': '^6.0.0' };
45
50
  /**
46
51
  * A reference to an account of a web app or a shop of a Shopify app: the one way a migration of the
47
52
  * product names the schema baukasten.
@@ -212,7 +217,7 @@ function packageProblems(files, baukasten) {
212
217
  const parsed = json(text);
213
218
  const manifest = parsed.kind === 'json' ? PACKAGE.safeParse(parsed.value) : null;
214
219
  if (manifest === null || !manifest.success) {
215
- return ['package.json is no JSON object, or its overrides are no object'];
220
+ return ['package.json is no JSON object, or its overrides or imports are no object'];
216
221
  }
217
222
  const own = new Set([
218
223
  baukasten.name,
@@ -220,7 +225,11 @@ function packageProblems(files, baukasten) {
220
225
  ...Object.keys(baukasten.peerDependencies)
221
226
  ]);
222
227
  const names = [...new Set(overridden(manifest.data.overrides))].filter((name) => own.has(name));
223
- return names.map((name) => `package.json overrides ${name}, which the baukasten brings itself; remove it`);
228
+ const problems = names.map((name) => `package.json overrides ${name}, which the baukasten brings itself; remove it`);
229
+ if (manifest.data.imports?.[LIB_IMPORT.key] !== LIB_IMPORT.target) {
230
+ problems.push(`package.json does not map imports "${LIB_IMPORT.key}" to "${LIB_IMPORT.target}", which the stubs import from`);
231
+ }
232
+ return problems;
224
233
  }
225
234
  function migrationProblems(files, art) {
226
235
  // Like the migration: every entry read, a folder failing loudly, then the .sql files.
@@ -1,4 +1,5 @@
1
- import type { Handle, HandleServerError, RequestEvent, ServerInit } from '@sveltejs/kit';
1
+ import type { RequestEvent } from '@sveltejs/kit';
2
+ import type { Handle, HandleServerError, ServerInit } from '@sveltejs/kit/hooks';
2
3
  import type { Language } from '../product.js';
3
4
  import { type Art } from './adapter/migrate.js';
4
5
  import { type Mail } from './config.js';
@@ -68,7 +69,7 @@ export interface CoreSpec<C extends CoreConfig, S> {
68
69
  export interface Core<C, S> {
69
70
  /**
70
71
  * The `init` of the hooks. SvelteKit runs it in `vite build` too, to prerender pages, with
71
- * `building` of `$app/environment` set: then it reads nothing and opens nothing, since the image is
72
+ * `building` of `$app/env` set: then it reads nothing and opens nothing, since the image is
72
73
  * built without a single variable.
73
74
  */
74
75
  init: (building: boolean) => ServerInit;
@@ -152,17 +152,26 @@ export function serverCore(spec) {
152
152
  });
153
153
  }
154
154
  };
155
- const handleError = ({ error, event, status, message }) => {
156
- // An unknown path is already in the request log.
157
- if (status === 404)
158
- return { message };
159
- (status >= 500 ? log.error : log.warn)('request failed', {
160
- method: event.request.method,
161
- path: event.url.pathname,
162
- status,
163
- error
164
- });
165
- return { message: status >= 500 ? 'Internal Error' : message };
155
+ // SvelteKit passes every error here; what a page shows of it stays SvelteKit's: the message of
156
+ // error(), its own safe message, or "Internal Error".
157
+ const handleError = (caught) => {
158
+ const request = { method: caught.event.request.method, path: caught.event.url.pathname };
159
+ switch (caught.kind) {
160
+ // The product raised it with error(), and its page says it.
161
+ case 'app':
162
+ return;
163
+ case 'framework':
164
+ case 'validation': {
165
+ const { status } = caught.error;
166
+ // An unknown path is already in the request log.
167
+ if (status !== 404)
168
+ log.warn('request failed', { ...request, status, error: caught.error });
169
+ return;
170
+ }
171
+ case 'unknown':
172
+ log.error('request failed', { ...request, status: 500, error: caught.error });
173
+ return;
174
+ }
166
175
  };
167
176
  return { init, handle, handleError, running };
168
177
  }
@@ -1,4 +1,5 @@
1
- import type { Handle, HandleServerError, RequestEvent, ServerInit } from '@sveltejs/kit';
1
+ import type { RequestEvent } from '@sveltejs/kit';
2
+ import type { Handle, HandleServerError, ServerInit } from '@sveltejs/kit/hooks';
2
3
  import type { z } from 'zod';
3
4
  import type { Product, ProductEnv } from '../product.js';
4
5
  import { type Account } from './accounts.js';
@@ -55,7 +56,7 @@ export interface Hooks<E extends ProductEnv = ProductEnv> {
55
56
  export interface Kit<E extends ProductEnv = ProductEnv> {
56
57
  /**
57
58
  * The `init` of the hooks. SvelteKit runs it in `vite build` too, to prerender pages, with
58
- * `building` of `$app/environment` set: then it reads nothing and opens nothing, since the image is
59
+ * `building` of `$app/env` set: then it reads nothing and opens nothing, since the image is
59
60
  * built without a single variable.
60
61
  */
61
62
  init(building: boolean): ServerInit;
@@ -85,7 +86,8 @@ export interface Kit<E extends ProductEnv = ProductEnv> {
85
86
  billing: {
86
87
  /**
87
88
  * A Checkout page for a price of the catalog, by its lookup key: a subscription, or a purchase.
88
- * An account with a running subscription gets none; the customer portal changes it.
89
+ * An account with a running subscription gets none; the customer portal changes it. Its
90
+ * address is Stripe's: `redirect` takes it with `{ external: true }`.
89
91
  */
90
92
  checkout(account: Account, order: Order): Promise<CheckoutPage>;
91
93
  /** The customer portal of the account, which leads back to the path `back`. */
@@ -471,7 +471,8 @@ export function createPages(services) {
471
471
  const account = requireAccount(event);
472
472
  if (!(await s.billing.hasCustomer(account.id)))
473
473
  redirect(303, '/account');
474
- redirect(303, await s.billing.portal(account, '/account'));
474
+ // The address of the portal comes from Stripe.
475
+ redirect(303, await s.billing.portal(account, '/account'), { external: true });
475
476
  },
476
477
  delete: async (event) => {
477
478
  const s = services();
@@ -23,12 +23,6 @@ export async function serve(load, headers) {
23
23
  log.error('unhandled rejection', { error });
24
24
  void exitAfterLog(1);
25
25
  });
26
- // adapter-node reads ORIGIN while it loads. An invalid PUBLIC_ORIGIN stays for the configuration,
27
- // which names it with every other problem in one line.
28
- const publicOrigin = process.env.PUBLIC_ORIGIN?.trim();
29
- if (publicOrigin !== undefined && URL.canParse(publicOrigin)) {
30
- process.env.ORIGIN = new URL(publicOrigin).origin;
31
- }
32
26
  let handler;
33
27
  try {
34
28
  // Loading runs `init`, which reads the configuration and starts the product.
@@ -38,7 +38,9 @@ const GRAPHQL = z.object({
38
38
  const SHOP_INFO = z.object({
39
39
  shop: z.object({
40
40
  id: z.string().startsWith('gid://shopify/Shop/'),
41
- email: z.string(),
41
+ // The mail about the data of a customer goes here, and the mailer would send it to every
42
+ // address it reads out of a list.
43
+ email: z.email(),
42
44
  plan: z.object({ partnerDevelopment: z.boolean() })
43
45
  }),
44
46
  currentAppInstallation: z.object({
@@ -200,8 +202,11 @@ export function shopifyApi(config, options) {
200
202
  throw new ShopifyFailed(`the Admin API refused: ${answer.errors.map((error) => error.code ?? error.message).join(', ')}`);
201
203
  case 'data': {
202
204
  const info = SHOP_INFO.safeParse(answer.data);
203
- if (!info.success)
204
- throw new ShopifyFailed('the shop came in an unknown form');
205
+ if (!info.success) {
206
+ // The fields name what did not hold; their values stay out of the log.
207
+ const fields = info.error.issues.map((issue) => issue.path.join('.') || 'the answer');
208
+ throw new ShopifyFailed(`the shop came in an unknown form: ${fields.join(', ')}`);
209
+ }
205
210
  return {
206
211
  shopId: info.data.shop.id,
207
212
  appId: info.data.currentAppInstallation.app.id,
@@ -1,4 +1,4 @@
1
- import type { Handle, HandleServerError, ServerInit } from '@sveltejs/kit';
1
+ import type { Handle, HandleServerError, ServerInit } from '@sveltejs/kit/hooks';
2
2
  import type { ProductEnv } from '../product.js';
3
3
  import type { Limits } from '../server/limits.js';
4
4
  import type { Log } from '../server/log.js';
@@ -40,7 +40,7 @@ export interface ShopifyHooks<E extends ProductEnv = ProductEnv> extends Webhook
40
40
  export interface ShopifyKit<E extends ProductEnv = ProductEnv> {
41
41
  /**
42
42
  * The `init` of the hooks. SvelteKit runs it in `vite build` too, with `building` of
43
- * `$app/environment` set: then it reads nothing and opens nothing.
43
+ * `$app/env` set: then it reads nothing and opens nothing.
44
44
  */
45
45
  init(building: boolean): ServerInit;
46
46
  handle: Handle;
package/dist/stubs.js CHANGED
@@ -1,6 +1,4 @@
1
1
  import { APP_BRIDGE_URL, COMPLIANCE_TOPICS, POLARIS_URL, SHOPIFY_API_VERSION, SHOPIFY_AUTH_PATH, SHOPIFY_WEBHOOK_PATH } from './shopify/constants.js';
2
- /** The alias of src/lib in the product: written out in an import here, svelte-package would resolve it. */
3
- const LIB = '$lib';
4
2
  const PAGES = [
5
3
  {
6
4
  route: 'account',
@@ -63,7 +61,7 @@ const PAGES = [
63
61
  }
64
62
  ];
65
63
  function serverPart(page) {
66
- return `import { kit } from '${LIB}/server/baukasten';
64
+ return `import { kit } from '#lib/server/baukasten.js';
67
65
 
68
66
  export const { ${page.server.join(', ')} } = kit.pages.${page.pages};
69
67
  `;
@@ -98,16 +96,16 @@ await start(() => import('./build/handler.js'));
98
96
  </html>
99
97
  `,
100
98
  'src/hooks.server.ts': `// The hooks of a product: the baukasten first, then the product's own handle.
101
- import { building } from '$app/environment';
99
+ import { building } from '$app/env';
102
100
  import { sequence } from '@sveltejs/kit/hooks';
103
- import { kit } from '${LIB}/server/baukasten';
104
- import { handle as own } from '${LIB}/server/handle';
101
+ import { kit } from '#lib/server/baukasten.js';
102
+ import { handle as own } from '#lib/server/handle.js';
105
103
 
106
104
  export const init = kit.init(building);
107
105
  export const handle = sequence(kit.handle, own);
108
106
  export const handleError = kit.handleError;
109
107
  `,
110
- 'src/routes/+layout.server.ts': `import { kit } from '${LIB}/server/baukasten';
108
+ 'src/routes/+layout.server.ts': `import { kit } from '#lib/server/baukasten.js';
111
109
 
112
110
  export const { load } = kit.pages.layout;
113
111
  `,
@@ -179,7 +177,7 @@ import product from '../../../baukasten.config';
179
177
  export const kit = baukasten(product);
180
178
  `,
181
179
  'src/lib/server/handle.ts': `// The product's own handle, after that of the baukasten (src/hooks.server.ts).
182
- import type { Handle } from '@sveltejs/kit';
180
+ import type { Handle } from '@sveltejs/kit/hooks';
183
181
 
184
182
  export const handle: Handle = ({ event, resolve }) => resolve(event);
185
183
  `
@@ -208,10 +206,10 @@ await start(() => import('./build/handler.js'));
208
206
  </html>
209
207
  `,
210
208
  'src/hooks.server.ts': `// The hooks of a Shopify app: the baukasten first, then the app's own handle.
211
- import { building } from '$app/environment';
209
+ import { building } from '$app/env';
212
210
  import { sequence } from '@sveltejs/kit/hooks';
213
- import { kit } from '${LIB}/server/baukasten';
214
- import { handle as own } from '${LIB}/server/handle';
211
+ import { kit } from '#lib/server/baukasten.js';
212
+ import { handle as own } from '#lib/server/handle.js';
215
213
 
216
214
  export const init = kit.init(building);
217
215
  export const handle = sequence(kit.handle, own);
@@ -280,7 +278,7 @@ import app from '../../../baukasten.config';
280
278
  export const kit = shopifyBaukasten(app);
281
279
  `,
282
280
  'src/lib/server/handle.ts': `// The app's own handle, after that of the baukasten (src/hooks.server.ts).
283
- import type { Handle } from '@sveltejs/kit';
281
+ import type { Handle } from '@sveltejs/kit/hooks';
284
282
 
285
283
  export const handle: Handle = ({ event, resolve }) => resolve(event);
286
284
  `
@@ -164,7 +164,7 @@ export async function startStripe(options = {}) {
164
164
  const payload = JSON.stringify({
165
165
  id: sendOptions.id ?? next('evt'),
166
166
  object: 'event',
167
- api_version: '2026-08-26.dahlia',
167
+ api_version: '2026-09-30.endive',
168
168
  created: Math.floor(Date.now() / 1_000),
169
169
  livemode: false,
170
170
  type,
@@ -16,10 +16,7 @@ export type ShopifyStandardVariable = (typeof SHOPIFY_STANDARD_VARIABLES)[number
16
16
  * without, its .env.example may name them, and none takes one for its own.
17
17
  */
18
18
  export declare const RETIRED_VARIABLES: readonly ["HOSTING_LOCATION"];
19
- /**
20
- * Every variable the baukasten reads in a web app. NODE_ENV comes from the image, and the server sets
21
- * ORIGIN from PUBLIC_ORIGIN.
22
- */
19
+ /** Every variable the baukasten reads in a web app. NODE_ENV comes from the image. */
23
20
  export declare const WEBAPP_VARIABLES: readonly ["PUBLIC_ORIGIN", "PORT", "DATABASE_URL", "SMTP_HOST", "SMTP_PORT", "MAIL_FROM", "MAIL_FROM_NAME", "OPERATOR_NAME", "OPERATOR_ADDRESS", "OPERATOR_REGISTER", "OPERATOR_VAT", "OPERATOR_JURISDICTION", "STRIPE_SECRET_KEY", "STRIPE_WEBHOOK_SECRET", "VERTRIEB_TOKEN", "LOG_LEVEL", "TEST_DATABASE_URL", "STRIPE_API_BASE"];
24
21
  export declare const SHOPIFY_VARIABLES: readonly ["PUBLIC_ORIGIN", "PORT", "DATABASE_URL", "SMTP_HOST", "SMTP_PORT", "MAIL_FROM", "MAIL_FROM_NAME", "OPERATOR_NAME", "OPERATOR_ADDRESS", "VERTRIEB_TOKEN", "SHOPIFY_API_SECRET", "SHOPIFY_TOKEN_KEY", "SHOPIFY_PARTNER_TOKEN", "SHOPIFY_PARTNER_ORG", "LOG_LEVEL", "TEST_DATABASE_URL", "SHOPIFY_API_BASE", "SHOPIFY_CLIENT_ID"];
25
22
  /**
package/dist/variables.js CHANGED
@@ -45,10 +45,7 @@ export const SHOPIFY_STANDARD_VARIABLES = [
45
45
  * without, its .env.example may name them, and none takes one for its own.
46
46
  */
47
47
  export const RETIRED_VARIABLES = ['HOSTING_LOCATION'];
48
- /**
49
- * Every variable the baukasten reads in a web app. NODE_ENV comes from the image, and the server sets
50
- * ORIGIN from PUBLIC_ORIGIN.
51
- */
48
+ /** Every variable the baukasten reads in a web app. NODE_ENV comes from the image. */
52
49
  export const WEBAPP_VARIABLES = [
53
50
  ...STANDARD_VARIABLES,
54
51
  'LOG_LEVEL',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tollwyn/baukasten",
3
- "version": "1.3.3",
3
+ "version": "2.0.0",
4
4
  "description": "What every product built on this kit shares: configuration, log and server, database with two-layer migrations, health, accounts with sessions and API keys, limits, mail, payment through Stripe, the numbers for sales, the frame and pages, the stubs that hang them into a product and the check of a product, and the tools to test one, its connection test among them; and for a Shopify app its installation with tokens, the frame of the admin, its webhooks, its plan through the Partner API and its privacy text.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -56,22 +56,22 @@
56
56
  "check:version": "node scripts/npm-version.ts"
57
57
  },
58
58
  "peerDependencies": {
59
- "@sveltejs/kit": "^2.70.0",
60
- "svelte": "^5.57.0"
59
+ "@sveltejs/kit": "^3.1.0",
60
+ "svelte": "^5.57.1"
61
61
  },
62
62
  "dependencies": {
63
- "nodemailer": "10.1.1",
63
+ "nodemailer": "10.1.4",
64
64
  "pg": "8.23.1",
65
65
  "smol-toml": "1.9.1",
66
- "stripe": "22.6.2",
66
+ "stripe": "23.0.0",
67
67
  "zod": "4.6.7"
68
68
  },
69
69
  "devDependencies": {
70
70
  "@eslint-community/eslint-plugin-eslint-comments": "4.8.1",
71
71
  "@eslint/js": "10.0.1",
72
- "@playwright/test": "1.64.0",
73
- "@sveltejs/kit": "2.70.3",
74
- "@sveltejs/package": "2.5.8",
72
+ "@playwright/test": "1.64.1",
73
+ "@sveltejs/kit": "3.1.0",
74
+ "@sveltejs/package": "3.0.1",
75
75
  "@sveltejs/vite-plugin-svelte": "7.3.1",
76
76
  "@types/node": "24.19.2",
77
77
  "@types/pg": "8.23.1",
@@ -82,15 +82,12 @@
82
82
  "globals": "17.13.0",
83
83
  "prettier": "3.9.10",
84
84
  "prettier-plugin-svelte": "4.1.1",
85
- "smtp-server": "3.19.22",
85
+ "smtp-server": "3.19.24",
86
86
  "svelte": "5.57.2",
87
87
  "svelte-check": "4.7.6",
88
88
  "typescript": "6.0.3",
89
89
  "typescript-eslint": "8.71.2",
90
90
  "vite": "8.3.4",
91
91
  "vitest": "5.0.4"
92
- },
93
- "overrides": {
94
- "cookie": "0.7.0"
95
92
  }
96
93
  }