@tollwyn/baukasten 2.0.0 → 3.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.
Files changed (46) hide show
  1. package/README.md +155 -11
  2. package/dist/check.d.ts +0 -2
  3. package/dist/check.js +167 -8
  4. package/dist/eslint.d.ts +2 -0
  5. package/dist/eslint.js +64 -0
  6. package/dist/gate.d.ts +32 -0
  7. package/dist/gate.js +49 -0
  8. package/dist/index.d.ts +4 -4
  9. package/dist/index.js +1 -1
  10. package/dist/knip.d.ts +14 -0
  11. package/dist/knip.js +25 -0
  12. package/dist/product.d.ts +4 -3
  13. package/dist/product.js +1 -1
  14. package/dist/server/adapter/migrate.d.ts +2 -1
  15. package/dist/server/billing.d.ts +3 -2
  16. package/dist/server/catalog.d.ts +1 -7
  17. package/dist/server/catalog.js +1 -1
  18. package/dist/server/config.d.ts +1 -1
  19. package/dist/server/core.d.ts +2 -2
  20. package/dist/server/endpoints.d.ts +0 -8
  21. package/dist/server/endpoints.js +1 -1
  22. package/dist/server/index.d.ts +3 -10
  23. package/dist/server/index.js +1 -2
  24. package/dist/server/messages.d.ts +1 -1
  25. package/dist/server/pages.d.ts +0 -3
  26. package/dist/server/pages.js +1 -1
  27. package/dist/server/ports.d.ts +3 -2
  28. package/dist/shopify/hook.d.ts +2 -1
  29. package/dist/shopify/index.d.ts +2 -7
  30. package/dist/shopify/index.js +0 -1
  31. package/dist/shopify/pages.d.ts +0 -2
  32. package/dist/shopify/pages.js +1 -1
  33. package/dist/shopify/ports.d.ts +2 -1
  34. package/dist/shopify/shops.d.ts +2 -5
  35. package/dist/shopify/shops.js +2 -2
  36. package/dist/testing/browser.d.ts +0 -2
  37. package/dist/testing/browser.js +1 -1
  38. package/dist/testing/index.d.ts +5 -5
  39. package/dist/testing/index.js +2 -2
  40. package/dist/testing/shopify.d.ts +2 -1
  41. package/dist/testing/smtp.d.ts +2 -3
  42. package/dist/testing/smtp.js +1 -1
  43. package/dist/testing/stripe.d.ts +5 -5
  44. package/dist/ui/Linked.svelte.d.ts +2 -2
  45. package/dist/ui/index.d.ts +0 -1
  46. package/package.json +12 -3
package/dist/knip.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /** The part of the configuration of knip that the preset sets. */
2
+ export interface KnipPreset {
3
+ entry: string[];
4
+ sveltekit: {
5
+ entry: string[];
6
+ };
7
+ playwright: {
8
+ config: string[];
9
+ entry: string[];
10
+ };
11
+ ignoreDependencies: string[];
12
+ }
13
+ declare const preset: KnipPreset;
14
+ export default preset;
package/dist/knip.js ADDED
@@ -0,0 +1,25 @@
1
+ // The knip preset of every product, which its knip.config.ts spreads and adds to (README, «The
2
+ // gate»). knip finds the routes, the hooks of server and client and the matchers through its plugin
3
+ // for SvelteKit, the stub server.js as the file Node starts, and the tests through Vitest; this names
4
+ // what only the baukasten knows, and what the plugin misses.
5
+ import { LINT_PLUGINS } from './gate.js';
6
+ const preset = {
7
+ // The baukasten loads it, in the migration command and the connection test.
8
+ entry: ['baukasten.config.ts'],
9
+ // SvelteKit loads the universal hooks, which the plugin does not name. Here, not under entry, a
10
+ // product without them gets no hint that the pattern finds nothing; the plugin still reads
11
+ // vite.config.ts for the rest.
12
+ sveltekit: { entry: ['src/hooks.{js,ts}'] },
13
+ // Read, not run: the configuration of Playwright may need the test database to load. Its tests lie
14
+ // in e2e/, the connection test of the baukasten among them, as Playwright finds them there. What
15
+ // else the configuration loads (globalSetup, a webServer, a reporter of its own) the product adds
16
+ // here itself.
17
+ playwright: {
18
+ config: [],
19
+ entry: ['playwright.config.ts', 'e2e/**/*.@(spec|test).?(c|m)[jt]s?(x)']
20
+ },
21
+ // What the baukasten imports from the product: the plugins of its ESLint config, and the server of
22
+ // the SMTP double.
23
+ ignoreDependencies: [...Object.keys(LINT_PLUGINS), 'smtp-server']
24
+ };
25
+ export default preset;
package/dist/product.d.ts CHANGED
@@ -9,7 +9,7 @@ export interface NavigationLink {
9
9
  label: string;
10
10
  }
11
11
  /** The grounds on which a product may process personal data, as the privacy policy names them. */
12
- export declare const LEGAL_BASES: readonly ["contract", "legitimateInterest"];
12
+ declare const LEGAL_BASES: readonly ["contract", "legitimateInterest"];
13
13
  export type LegalBasis = (typeof LEGAL_BASES)[number];
14
14
  /**
15
15
  * What covers personal data that go to a recipient: a country with adequate protection (only
@@ -77,14 +77,14 @@ export interface ProductLegal {
77
77
  };
78
78
  }
79
79
  /** A price of a subscription: an amount in the smallest unit of the currency, per month or year. */
80
- export interface SubscriptionPrice {
80
+ interface SubscriptionPrice {
81
81
  /** The price at Stripe has this lookup key; a new amount becomes a new price under the same key. */
82
82
  lookupKey: string;
83
83
  amount: number;
84
84
  interval: 'month' | 'year';
85
85
  }
86
86
  /** A price paid once, in the smallest unit of the currency. */
87
- export interface PurchasePrice {
87
+ interface PurchasePrice {
88
88
  lookupKey: string;
89
89
  amount: number;
90
90
  }
@@ -159,3 +159,4 @@ export interface Brand {
159
159
  export declare function isProduct(value: unknown): value is Product;
160
160
  /** Declares the configuration of the product; anything wrong with it stops the product loudly. */
161
161
  export declare function defineProduct<const E extends ProductEnv>(product: Product<E>): Product<E>;
162
+ export {};
package/dist/product.js CHANGED
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { BAUKASTEN_VARIABLES } from './variables.js';
3
3
  export const LANGUAGES = ['en', 'de'];
4
4
  /** The grounds on which a product may process personal data, as the privacy policy names them. */
5
- export const LEGAL_BASES = ['contract', 'legitimateInterest'];
5
+ const LEGAL_BASES = ['contract', 'legitimateInterest'];
6
6
  /**
7
7
  * What covers personal data that go to a recipient: a country with adequate protection (only
8
8
  * Switzerland, the EEA and the countries in Annex 1 of the Swiss Data Protection Ordinance, DSV), the
@@ -8,7 +8,7 @@ export interface MigrationSources {
8
8
  /** The folder of the product's migrations; a product without one has none. */
9
9
  product: string;
10
10
  }
11
- export type ByLayer = Record<Layer, string[]>;
11
+ type ByLayer = Record<Layer, string[]>;
12
12
  /** What a run applied, and what the database had ahead of this version. */
13
13
  export interface MigrateResult {
14
14
  applied: ByLayer;
@@ -19,3 +19,4 @@ export declare function migrationSources(root: string, art: Art): MigrationSourc
19
19
  /** What the database still needs of this version and what forbids migrating it, for /health/deep. */
20
20
  export declare function migrationStatus(db: Queryable, sources: MigrationSources): Promise<MigrationStatus>;
21
21
  export declare function migrate(databaseUrl: string, sources: MigrationSources): Promise<MigrateResult>;
22
+ export {};
@@ -11,7 +11,7 @@ export declare class StripeFailed extends Error {
11
11
  constructor(kind: string, message: string, options?: ErrorOptions);
12
12
  }
13
13
  /** A subscription as the product gets it: its product and the lookup key of its price. */
14
- export interface Subscription {
14
+ interface Subscription {
15
15
  id: string;
16
16
  status: SubscriptionStatus;
17
17
  product: string;
@@ -57,7 +57,7 @@ export type CheckoutPage = {
57
57
  } | {
58
58
  kind: 'subscribed';
59
59
  };
60
- export type Received = {
60
+ type Received = {
61
61
  kind: 'invalid';
62
62
  } | {
63
63
  kind: 'applied';
@@ -92,3 +92,4 @@ export declare function createBilling(options: {
92
92
  /** The sentence by the box for the terms in Checkout, in Markdown, with their link. */
93
93
  termsMessage: (termsUrl: string) => string;
94
94
  }): Billing;
95
+ export {};
@@ -1,5 +1,5 @@
1
1
  import type { Catalog } from '../product.js';
2
- import type { NewPrice, PortalConfiguration, StripeApi, StripePrice } from './ports.js';
2
+ import type { NewPrice, StripeApi, StripePrice } from './ports.js';
3
3
  /** The name and the address of the product, which the customer portal shows. */
4
4
  export interface Shop {
5
5
  name: string;
@@ -43,12 +43,6 @@ export interface CatalogAction {
43
43
  export declare function pricesOf(catalog: Catalog): NewPrice[];
44
44
  /** Whether the price at Stripe charges what the catalog says. */
45
45
  export declare function priceFits(found: StripePrice, wanted: NewPrice): boolean;
46
- /**
47
- * The default configuration of the customer portal names the product and links its own pages: an
48
- * account copied from another one brings that one's along. `ids` holds the price at Stripe of each
49
- * lookup key that has one; null while a price the portal offers has none yet.
50
- */
51
- export declare function portalConfiguration(catalog: Catalog, shop: Shop, ids: ReadonlyMap<string, string>): PortalConfiguration | null;
52
46
  /**
53
47
  * Whether `found` holds every value of `wanted`. Lists hold the same items in any order: Stripe
54
48
  * need not keep the order it was given.
@@ -44,7 +44,7 @@ export function priceFits(found, wanted) {
44
44
  * account copied from another one brings that one's along. `ids` holds the price at Stripe of each
45
45
  * lookup key that has one; null while a price the portal offers has none yet.
46
46
  */
47
- export function portalConfiguration(catalog, shop, ids) {
47
+ function portalConfiguration(catalog, shop, ids) {
48
48
  const subscriptions = catalog.products.flatMap((product) => product.kind === 'subscription' ? [product] : []);
49
49
  const prices = subscriptions.reduce((count, product) => count + product.prices.length, 0);
50
50
  const allowed = [
@@ -18,7 +18,7 @@ export type Mail = {
18
18
  };
19
19
  /** The mode of Stripe, by the prefix of the key: test until the delivery service switches to live. */
20
20
  export type StripeMode = 'test' | 'live';
21
- export type Stripe = {
21
+ type Stripe = {
22
22
  kind: 'stripe';
23
23
  secretKey: string;
24
24
  webhookSecret: string;
@@ -19,7 +19,7 @@ export interface CoreConfig {
19
19
  missing: readonly string[];
20
20
  }
21
21
  /** Pool, configuration, log, mail and limits of what runs, for the hooks of the product. */
22
- export interface CoreContext<C> {
22
+ interface CoreContext<C> {
23
23
  config: C;
24
24
  db: Db;
25
25
  log: Log;
@@ -27,7 +27,7 @@ export interface CoreContext<C> {
27
27
  limits: Limits;
28
28
  }
29
29
  /** The hooks of the product the core calls; the art calls the others. */
30
- export interface CoreHooks<C> {
30
+ interface CoreHooks<C> {
31
31
  checks?: Record<string, (context: CoreContext<C>) => Promise<void>>;
32
32
  start?: (context: CoreContext<C>) => Promise<void> | void;
33
33
  stop?: (context: CoreContext<C>) => Promise<void> | void;
@@ -31,14 +31,6 @@ export declare function signupBody(m: Messages, terms: string): z.ZodObject<{
31
31
  acting_for_business: z.ZodLiteral<true>;
32
32
  via: z.ZodOptional<z.ZodString>;
33
33
  }, z.core.$strip>;
34
- /**
35
- * The body of a Checkout over the API: a price of the catalog by its lookup key, and a quantity,
36
- * which the price decides on (checkout below).
37
- */
38
- export declare function checkoutBody(m: Messages): z.ZodObject<{
39
- price: z.ZodString;
40
- quantity: z.ZodOptional<z.ZodUnknown>;
41
- }, z.core.$strip>;
42
34
  /** The answer of a path of the baukasten's API, or null for any other path. */
43
35
  export declare function serveApi(s: Services, event: RequestEvent): Promise<Response> | null;
44
36
  export {};
@@ -84,7 +84,7 @@ async function signup(s, event) {
84
84
  * The body of a Checkout over the API: a price of the catalog by its lookup key, and a quantity,
85
85
  * which the price decides on (checkout below).
86
86
  */
87
- export function checkoutBody(m) {
87
+ function checkoutBody(m) {
88
88
  return z.object({ price: z.string(m.api.price), quantity: z.unknown().optional() }, m.api.notAnObject);
89
89
  }
90
90
  function invalid(m, path, message) {
@@ -1,18 +1,11 @@
1
- export type { Account, ApiKey } from './accounts.js';
2
1
  export { log } from './adapter/log.js';
3
2
  export { ApiError } from './api.js';
4
- export { StripeFailed, type CheckoutPage, type Order, type Purchase, type Subscription, type SubscriptionChange } from './billing.js';
5
- export type { Config, Mail as MailConfig, Operator, Register, Stripe } from './config.js';
6
3
  export { CheckFailed } from './health.js';
7
4
  export { baukasten, type Context, type Hooks, type Kit } from './hook.js';
8
- export { LIMITS, type Limits, type Rule } from './limits.js';
9
5
  export type { Log } from './log.js';
10
6
  export { MailFailed } from './mail.js';
11
- export type { OpenApiDocument } from './openapi.js';
12
- export type { Pages } from './pages.js';
13
- export type { Db, Mail, Mailer, Queryable, SubscriptionStatus } from './ports.js';
14
- export { periodic, type Run, type RunOptions } from './runs.js';
15
- export type { ProductNumbers } from './sales.js';
16
- export { start, type NodeHandler } from './start.js';
7
+ export type { Db, Mail, Mailer, Queryable } from './ports.js';
8
+ export { periodic } from './runs.js';
9
+ export { start } from './start.js';
17
10
  export { KEY_RIGHTS, WEBHOOK_EVENTS, WEBHOOK_PATH } from './stripe.js';
18
11
  export { requireAccount, tooMany } from './web.js';
@@ -1,9 +1,8 @@
1
+ // The server entry of the baukasten; nothing here may reach the browser.
1
2
  export { log } from './adapter/log.js';
2
3
  export { ApiError } from './api.js';
3
- export { StripeFailed } from './billing.js';
4
4
  export { CheckFailed } from './health.js';
5
5
  export { baukasten } from './hook.js';
6
- export { LIMITS } from './limits.js';
7
6
  export { MailFailed } from './mail.js';
8
7
  export { periodic } from './runs.js';
9
8
  export { start } from './start.js';
@@ -1,5 +1,5 @@
1
1
  import type { Language } from '../product.js';
2
- export interface MailText {
2
+ interface MailText {
3
3
  subject: string;
4
4
  text: string;
5
5
  }
@@ -1,13 +1,10 @@
1
1
  import { type RequestEvent } from '@sveltejs/kit';
2
- import type { Brand } from '../product.js';
3
2
  import type { AccountData, ConfirmData, FrameData, LegalData, LoginData, LogoutData, ResetData, SignupData, VerifyData } from '../ui/data.js';
4
3
  import { type Services } from './services.js';
5
4
  type LoadEvent = {
6
5
  locals: App.Locals;
7
6
  url: URL;
8
7
  };
9
- /** The marks of the product as the frame shows them: the picture of a shared link at its whole address. */
10
- export declare function frameBrand(brand: Brand | undefined, origin: string): FrameData['brand'];
11
8
  export type Pages = ReturnType<typeof createPages>;
12
9
  export declare function createPages(services: () => Services): {
13
10
  layout: {
@@ -9,7 +9,7 @@ import { sendLink, signUp } from './services.js';
9
9
  import { parseVia } from './via.js';
10
10
  import { clearSessionCookie, requireAccount, safeNext, SESSION_COOKIE, setSessionCookie, tooMany } from './web.js';
11
11
  /** The marks of the product as the frame shows them: the picture of a shared link at its whole address. */
12
- export function frameBrand(brand, origin) {
12
+ function frameBrand(brand, origin) {
13
13
  if (brand === undefined)
14
14
  return null;
15
15
  return {
@@ -47,7 +47,7 @@ export interface Mailer {
47
47
  check(): Promise<void>;
48
48
  }
49
49
  /** A product at Stripe as the catalog compares it. */
50
- export interface StripeProduct {
50
+ interface StripeProduct {
51
51
  id: string;
52
52
  name: string;
53
53
  active: boolean;
@@ -127,7 +127,7 @@ export interface PortalConfiguration {
127
127
  }
128
128
  export type SubscriptionStatus = 'incomplete' | 'incomplete_expired' | 'trialing' | 'active' | 'past_due' | 'canceled' | 'unpaid' | 'paused';
129
129
  /** A subscription at Stripe with its one item. */
130
- export interface StripeSubscription {
130
+ interface StripeSubscription {
131
131
  id: string;
132
132
  customerId: string;
133
133
  status: SubscriptionStatus;
@@ -278,3 +278,4 @@ export interface StripeApi {
278
278
  kind: 'invalid';
279
279
  };
280
280
  }
281
+ export {};
@@ -9,7 +9,7 @@ import { type ShopifyConfig } from './config.js';
9
9
  import { type Plan } from './shops.js';
10
10
  import { type WebhookHooks } from './webhooks.js';
11
11
  /** The shop of a request that got in. */
12
- export interface ShopSession {
12
+ interface ShopSession {
13
13
  /** Its permanent domain, like example.myshopify.com. */
14
14
  domain: string;
15
15
  plan: Exclude<Plan, {
@@ -58,3 +58,4 @@ export interface ShopifyKit<E extends ProductEnv = ProductEnv> {
58
58
  admin(shop: string): AdminApi;
59
59
  }
60
60
  export declare function shopifyBaukasten<E extends ProductEnv>(app: ShopifyApp<E>, hooks?: ShopifyHooks<E>): ShopifyKit<E>;
61
+ export {};
@@ -1,18 +1,13 @@
1
1
  import { type NodeHandler } from '../server/start.js';
2
2
  export { log } from '../server/adapter/log.js';
3
3
  export { CheckFailed } from '../server/health.js';
4
- export { LIMITS, type Limits, type Rule } from '../server/limits.js';
5
4
  export type { Log } from '../server/log.js';
6
5
  export { MailFailed } from '../server/mail.js';
7
6
  export type { Db, Mail, Mailer, Queryable } from '../server/ports.js';
8
- export { periodic, type Run, type RunOptions } from '../server/runs.js';
9
- export type { NodeHandler } from '../server/start.js';
7
+ export { periodic } from '../server/runs.js';
10
8
  export { AdminRefused, ShopGone, type AdminApi } from './admin.js';
11
- export type { ShopifyConfig } from './config.js';
12
9
  export { SHOPIFY_API_VERSION, SHOPIFY_WEBHOOK_PATH } from './constants.js';
13
- export { shopifyBaukasten, type ShopifyContext, type ShopifyHooks, type ShopifyKit, type ShopSession } from './hook.js';
14
- export type { Plan } from './shops.js';
15
- export type { CustomerRequest, Delivery } from './webhooks.js';
10
+ export { shopifyBaukasten, type ShopifyContext, type ShopifyHooks, type ShopifyKit } from './hook.js';
16
11
  /** The server of a Shopify app, called by its stub server.js with the handler of adapter-node. */
17
12
  export declare function start(load: () => Promise<{
18
13
  handler: NodeHandler;
@@ -3,7 +3,6 @@ import { serve } from '../server/start.js';
3
3
  import { SHOPIFY_SECURITY_HEADERS } from './headers.js';
4
4
  export { log } from '../server/adapter/log.js';
5
5
  export { CheckFailed } from '../server/health.js';
6
- export { LIMITS } from '../server/limits.js';
7
6
  export { MailFailed } from '../server/mail.js';
8
7
  export { periodic } from '../server/runs.js';
9
8
  export { AdminRefused, ShopGone } from './admin.js';
@@ -1,8 +1,6 @@
1
1
  import type { Language } from '../product.js';
2
2
  import type { LegalData } from '../ui/data.js';
3
3
  import type { ShopifyTexts } from './texts.js';
4
- /** Text into HTML, in an element or a quoted attribute. */
5
- export declare function escapeHtml(text: string): string;
6
4
  /** frame-ancestors for the admin of `shop`, or for none outside it. */
7
5
  export declare function frameAncestors(shop: string | null): string;
8
6
  /**
@@ -1,6 +1,6 @@
1
1
  import { APP_BRIDGE_URL, SHOPIFY_ADMIN, SHOPIFY_CDN, SHOPIFY_SCRIPTS } from './constants.js';
2
2
  /** Text into HTML, in an element or a quoted attribute. */
3
- export function escapeHtml(text) {
3
+ function escapeHtml(text) {
4
4
  return text
5
5
  .replaceAll('&', '&amp;')
6
6
  .replaceAll('<', '&lt;')
@@ -11,7 +11,7 @@ export interface ShopTokens {
11
11
  * Why Shopify gave no tokens: `invalid` for an ID token or refresh token it no longer takes (the shop
12
12
  * must open the app again), `failed` for anything else, which a later try may get past.
13
13
  */
14
- export type TokenRefusal = {
14
+ type TokenRefusal = {
15
15
  kind: 'invalid';
16
16
  } | {
17
17
  kind: 'failed';
@@ -75,3 +75,4 @@ export interface ShopifyApi {
75
75
  /** Whether the Partner API takes the token: a query without data of a shop, for /health/deep. */
76
76
  partnerCheck(): Promise<void>;
77
77
  }
78
+ export {};
@@ -3,10 +3,6 @@ import type { Db, Queryable } from '../server/ports.js';
3
3
  import type { ShopifyPlan } from './app.js';
4
4
  import type { ShopifyApi } from './ports.js';
5
5
  import { type SealKey } from './seal.js';
6
- /** A token is refreshed when it ends within this time, so that no request runs into its end. */
7
- export declare const REFRESH_BEFORE_MS: number;
8
- /** The plan of a shop is asked again after this time, and at once after the plan page. */
9
- export declare const PLAN_FRESH_MS: number;
10
6
  export type Plan = {
11
7
  kind: 'none';
12
8
  } | {
@@ -15,7 +11,7 @@ export type Plan = {
15
11
  /** Until when it runs as a trial; null without one. */
16
12
  trialEndsAt: Date | null;
17
13
  };
18
- export type Entry = {
14
+ type Entry = {
19
15
  kind: 'in';
20
16
  }
21
17
  /** Shopify no longer takes the ID token: App Bridge fetches a new one. */
@@ -74,3 +70,4 @@ export declare function createShops(deps: {
74
70
  /** 12 random bytes for each sealed token. */
75
71
  nonce: () => Uint8Array;
76
72
  }): Shops;
73
+ export {};
@@ -1,9 +1,9 @@
1
1
  import { scopesCover } from './scopes.js';
2
2
  import { open, seal } from './seal.js';
3
3
  /** A token is refreshed when it ends within this time, so that no request runs into its end. */
4
- export const REFRESH_BEFORE_MS = 5 * 60_000;
4
+ const REFRESH_BEFORE_MS = 5 * 60_000;
5
5
  /** The plan of a shop is asked again after this time, and at once after the plan page. */
6
- export const PLAN_FRESH_MS = 10 * 60_000;
6
+ const PLAN_FRESH_MS = 10 * 60_000;
7
7
  export function createShops(deps) {
8
8
  const { db, api, key, log, now } = deps;
9
9
  /** Where a token belongs: a sealed one opens only there. */
@@ -1,5 +1,3 @@
1
- /** What the frame sets once the page is hydrated. */
2
- export declare const HYDRATED = "html[data-hydrated]";
3
1
  /** What these helpers need of a page of Playwright. */
4
2
  export interface PageLike {
5
3
  goto(url: string): Promise<unknown>;
@@ -1,5 +1,5 @@
1
1
  /** What the frame sets once the page is hydrated. */
2
- export const HYDRATED = 'html[data-hydrated]';
2
+ const HYDRATED = 'html[data-hydrated]';
3
3
  /** Waits until the page is interactive: filled before, a field can lose what was typed. */
4
4
  export async function waitForHydration(page) {
5
5
  await page.waitForSelector(HYDRATED, { state: 'attached' });
@@ -1,9 +1,9 @@
1
- export { freePort, spawnNode, startApp, type AppProcess, type LogLine, type RunningApp } from './app.js';
1
+ export { freePort, spawnNode, startApp, type LogLine, type RunningApp } from './app.js';
2
2
  export { connectionTest } from './connection.js';
3
- export { HYDRATED, newCaller, open, waitForHydration, type PageLike } from './browser.js';
3
+ export { newCaller, open, waitForHydration } from './browser.js';
4
4
  export { createTestDatabase, type TestDatabase } from './database.js';
5
5
  export { envExampleProblems } from './env-example.js';
6
6
  export { shopifyConnectionTest } from './shopify-connection.js';
7
- export { startShopify, type AdminAnswer, type DoubleShop, type ShopifyDouble } from './shopify.js';
8
- export { linkIn, startSmtp, type ReceivedMail, type SmtpDouble } from './smtp.js';
9
- export { startStripe, stripeSignature, type DoubleEndpoint, type DoublePrice, type DoubleSession, type DoubleSubscription, type StripeDouble } from './stripe.js';
7
+ export { startShopify, type AdminAnswer, type ShopifyDouble } from './shopify.js';
8
+ export { linkIn, startSmtp, type SmtpDouble } from './smtp.js';
9
+ export { startStripe, type StripeDouble } from './stripe.js';
@@ -1,9 +1,9 @@
1
1
  export { freePort, spawnNode, startApp } from './app.js';
2
2
  export { connectionTest } from './connection.js';
3
- export { HYDRATED, newCaller, open, waitForHydration } from './browser.js';
3
+ export { newCaller, open, waitForHydration } from './browser.js';
4
4
  export { createTestDatabase } from './database.js';
5
5
  export { envExampleProblems } from './env-example.js';
6
6
  export { shopifyConnectionTest } from './shopify-connection.js';
7
7
  export { startShopify } from './shopify.js';
8
8
  export { linkIn, startSmtp } from './smtp.js';
9
- export { startStripe, stripeSignature } from './stripe.js';
9
+ export { startStripe } from './stripe.js';
@@ -1,4 +1,4 @@
1
- export interface DoubleShop {
1
+ interface DoubleShop {
2
2
  domain: string;
3
3
  /** gid://shopify/Shop/… */
4
4
  id: string;
@@ -69,3 +69,4 @@ export interface ShopifyDouble {
69
69
  export declare function startShopify(options: {
70
70
  scopes: string;
71
71
  }): Promise<ShopifyDouble>;
72
+ export {};
@@ -1,4 +1,4 @@
1
- export interface ReceivedMail {
1
+ interface ReceivedMail {
2
2
  /** The recipients of the envelope, in small letters. */
3
3
  to: string[];
4
4
  /** The From header, decoded: name and address. */
@@ -26,8 +26,6 @@ export interface SmtpDouble {
26
26
  accept(to: string): void;
27
27
  stop(): Promise<void>;
28
28
  }
29
- /** Words like `=?UTF-8?Q?Gr=C3=BCezi?=` in a header; the space between two words goes with them. */
30
- export declare function decodeWords(value: string): string;
31
29
  /** The headers and the text of a plain-text message as SMTP carries it. */
32
30
  export declare function parseMessage(raw: Buffer): {
33
31
  headers: Map<string, string>;
@@ -36,3 +34,4 @@ export declare function parseMessage(raw: Buffer): {
36
34
  /** The first link in a text that starts with `prefix`. */
37
35
  export declare function linkIn(text: string, prefix: string): string;
38
36
  export declare function startSmtp(): Promise<SmtpDouble>;
37
+ export {};
@@ -5,7 +5,7 @@
5
5
  // carries it.
6
6
  import { EventEmitter } from 'node:events';
7
7
  /** Words like `=?UTF-8?Q?Gr=C3=BCezi?=` in a header; the space between two words goes with them. */
8
- export function decodeWords(value) {
8
+ function decodeWords(value) {
9
9
  return value
10
10
  .replace(/(=\?[^?]+\?[QqBb]\?[^?]*\?=)\s+(?==\?)/g, '$1')
11
11
  .replace(/=\?([^?]+)\?([QqBb])\?([^?]*)\?=/g, (_, charset, kind, text) => {
@@ -1,11 +1,11 @@
1
1
  /** A value of the JSON the double answers. */
2
- export type Json = string | number | boolean | null | Json[] | {
2
+ type Json = string | number | boolean | null | Json[] | {
3
3
  [key: string]: Json;
4
4
  };
5
5
  type JsonObject = {
6
6
  [key: string]: Json;
7
7
  };
8
- export interface DoublePrice {
8
+ interface DoublePrice {
9
9
  id: string;
10
10
  object: 'price';
11
11
  product: string;
@@ -19,7 +19,7 @@ export interface DoublePrice {
19
19
  interval_count: number;
20
20
  } | null;
21
21
  }
22
- export interface DoubleSubscription {
22
+ interface DoubleSubscription {
23
23
  id: string;
24
24
  object: 'subscription';
25
25
  customer: string;
@@ -35,7 +35,7 @@ export interface DoubleSubscription {
35
35
  }[];
36
36
  };
37
37
  }
38
- export interface DoubleSession {
38
+ interface DoubleSession {
39
39
  id: string;
40
40
  object: 'checkout.session';
41
41
  mode: string;
@@ -59,7 +59,7 @@ export interface DoubleSession {
59
59
  /** The whole request, as the API got it. */
60
60
  request: JsonObject;
61
61
  }
62
- export interface DoubleEndpoint {
62
+ interface DoubleEndpoint {
63
63
  id: string;
64
64
  object: 'webhook_endpoint';
65
65
  url: string;
@@ -1,6 +1,6 @@
1
- import type { Linked } from '../texts.js';
1
+ import type { Linked as LinkedText } from '../texts.js';
2
2
  type $$ComponentProps = {
3
- text: Linked;
3
+ text: LinkedText;
4
4
  href: string;
5
5
  };
6
6
  declare const Linked: import("svelte").Component<$$ComponentProps, {}, "">;
@@ -12,4 +12,3 @@ export { default as LogoutPage } from './LogoutPage.svelte';
12
12
  export { default as ResetPasswordPage } from './ResetPasswordPage.svelte';
13
13
  export { default as SignupPage } from './SignupPage.svelte';
14
14
  export { default as VerifyEmailPage } from './VerifyEmailPage.svelte';
15
- export type * from './data.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tollwyn/baukasten",
3
- "version": "2.0.0",
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.",
3
+ "version": "3.0.0",
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, the ESLint config and knip preset of its gate, 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",
7
7
  "engines": {
@@ -35,6 +35,14 @@
35
35
  "types": "./dist/ui/index.d.ts",
36
36
  "svelte": "./dist/ui/index.js",
37
37
  "default": "./dist/ui/index.js"
38
+ },
39
+ "./eslint": {
40
+ "types": "./dist/eslint.d.ts",
41
+ "default": "./dist/eslint.js"
42
+ },
43
+ "./knip": {
44
+ "types": "./dist/knip.d.ts",
45
+ "default": "./dist/knip.js"
38
46
  }
39
47
  },
40
48
  "bin": {
@@ -52,7 +60,7 @@
52
60
  "test:db": "node ../scripts/test-db.mjs mit vitest run --config vitest.db.config.ts",
53
61
  "test:e2e": "npm run muster && npm --prefix muster run test:e2e && npm --prefix muster-shopify run test:e2e",
54
62
  "typecheck": "svelte-check --tsconfig ./tsconfig.json --fail-on-warnings && npm --prefix muster run check && npm --prefix muster-shopify run check",
55
- "lint": "eslint . --max-warnings 0 && prettier --check . && npm --prefix muster run lint && npm --prefix muster-shopify run lint",
63
+ "lint": "eslint . --max-warnings 0 && knip && prettier --check . && npm --prefix muster run lint && npm --prefix muster-shopify run lint",
56
64
  "check:version": "node scripts/npm-version.ts"
57
65
  },
58
66
  "peerDependencies": {
@@ -80,6 +88,7 @@
80
88
  "eslint-config-prettier": "10.1.8",
81
89
  "eslint-plugin-svelte": "3.23.1",
82
90
  "globals": "17.13.0",
91
+ "knip": "6.41.0",
83
92
  "prettier": "3.9.10",
84
93
  "prettier-plugin-svelte": "4.1.1",
85
94
  "smtp-server": "3.19.24",