@linkforty/core 1.25.4 → 1.26.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
@@ -241,6 +241,29 @@ Automatically redirects users to the appropriate URL based on device type (iOS/A
241
241
 
242
242
  **Mobile interstitial:** When a link has `appScheme` configured and a store fallback URL (iOS App Store or Google Play), mobile requests receive a smart interstitial page instead of a raw 302 redirect. The interstitial tries to open the app via URI scheme and falls back to the app store after 1.5 seconds. This handles the case where a 302 to a custom URI scheme fails silently when the app is not installed. URL fragments are preserved through the redirect, enabling patterns like E2E encryption where the decryption key lives in the fragment.
243
243
 
244
+ **Launchpad page (desktop):** A link to app-only content has nowhere to send a desktop visitor. When the chain resolves no web destination (link → template → workspace `appConfig`), a desktop request gets a hosted landing page instead of an error: the link's title, description and image (`ogTitle` / `ogDescription` / `ogImageUrl`, falling back to `title` / `description`), the app's icon and name, App Store / Google Play buttons, and a QR code so the visitor can finish on their phone. The page is `noindex`, sent with `Cache-Control: no-store` and a content-security policy that allows no script without a per-response nonce, and it never navigates on its own — no timers, no automatic scheme attempts.
245
+
246
+ By default it appears **only** where the alternative is nothing; a link that resolves to a destination still gets its 302. Two knobs change that:
247
+
248
+ - `organizations.settings.launchpad` (per workspace):
249
+
250
+ ```json
251
+ {
252
+ "launchpad": {
253
+ "desktop": "no-destination", // "no-destination" (default) | "always" | "off"
254
+ "appName": "Ride Alert",
255
+ "appIconUrl": "https://cdn.example/icon.png",
256
+ "accentColor": "#0f766e"
257
+ }
258
+ }
259
+ ```
260
+
261
+ - `links.launchpad_mode` (per link, `launchpadMode` on the links API): `inherit` (default), `on` or `off`. The link's value wins over the workspace's.
262
+
263
+ With `desktop: "off"` (or `launchpad_mode: "off"`), a link with no web destination gets the plain "This link opens in an app" page instead.
264
+
265
+ Two hooks on `RedirectRouteOptions` let a host application extend the page without forking it — see [Server Options](#server-options).
266
+
244
267
  ### QR Codes
245
268
 
246
269
  ```bash
@@ -322,9 +345,28 @@ interface ServerOptions {
322
345
  };
323
346
  logger?: boolean; // Enable Fastify logger (default: true)
324
347
  trustProxy?: boolean | number; // Trust X-Forwarded-For when behind a proxy (default: false)
348
+ redirect?: RedirectRouteOptions; // See below
349
+ }
350
+
351
+ interface RedirectRouteOptions {
352
+ abuseReportUrl?: string; // Linked from the link-safety warning page
353
+ launchpad?: {
354
+ // Supply richer content for the launchpad page than the link row carries:
355
+ // a rendered share image, a templated hero. Return null for the default.
356
+ // A hook that throws is logged and treated as null — the page never fails
357
+ // because of it. `heroHtml` is inserted unescaped: render it yourself,
358
+ // never from end-user input.
359
+ resolveContent?: (link, settings) => Promise<LaunchpadContent | null>;
360
+ // Endpoint that receives `{ linkId, event }` beacons from the page —
361
+ // "view" on load, "cta_ios" / "cta_android" / "cta_open" on tap. No
362
+ // cookies or identifiers. Unset means the page sends nothing.
363
+ beaconUrl?: string;
364
+ };
325
365
  }
326
366
  ```
327
367
 
368
+ `renderLaunchpadPage()`, `defaultLaunchpadContent()` and `shouldServeLaunchpadOnDesktop()` are exported so a host can render the same page elsewhere (a settings preview, for instance).
369
+
328
370
  ### Running behind a reverse proxy
329
371
 
330
372
  When Core runs behind a reverse proxy, CDN, or load balancer, set `trustProxy` so the server uses the real client IP from `X-Forwarded-For` for redirect targeting, geo, attribution, and fingerprinting. Pass it when creating the server (e.g. `trustProxy: true` or a number of proxy hops) or set the `TRUST_PROXY` environment variable (e.g. `TRUST_PROXY=1`). Client-provided `ipAddress` in the SDK install request body is **not** used as the trusted IP; it is optional debug metadata only and must not be relied on for attribution.
@@ -378,6 +420,7 @@ Core does not create a `users` table. Authentication and user management are the
378
420
  | og_description | TEXT | Open Graph description |
379
421
  | og_image_url | TEXT | Open Graph image URL |
380
422
  | og_type | VARCHAR(50) | Open Graph type (default: "website") |
423
+ | launchpad_mode | VARCHAR(10) | Launchpad page: inherit / on / off |
381
424
  | attribution_window_hours| INTEGER | Install attribution window (default: 168)|
382
425
  | is_active | BOOLEAN | Active status |
383
426
  | expires_at | TIMESTAMP | Expiration date |
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { FastifyInstance } from 'fastify';
2
2
  import { DatabaseOptions } from './lib/database.js';
3
+ import { type RedirectRouteOptions } from './routes/redirect.js';
3
4
  /**
4
5
  * Configuration options for creating a LinkForty server instance.
5
6
  */
@@ -14,6 +15,8 @@ export interface ServerOptions {
14
15
  logger?: boolean;
15
16
  /** When true or a number (proxy hop count), Fastify trusts X-Forwarded-For so request.ip is the real client IP. Set when behind a reverse proxy. */
16
17
  trustProxy?: boolean | number;
18
+ /** Options for the redirect routes: abuse-report link, launchpad page hooks. */
19
+ redirect?: RedirectRouteOptions;
17
20
  }
18
21
  /**
19
22
  * Create and configure a LinkForty Fastify server instance.
@@ -31,7 +34,9 @@ export * from './lib/database.js';
31
34
  export * from './lib/fingerprint.js';
32
35
  export * from './lib/webhook.js';
33
36
  export * from './lib/link-safety.js';
37
+ export * from './lib/launchpad.js';
34
38
  export * from './lib/event-emitter.js';
35
39
  export * from './types/index.js';
40
+ export type { RedirectRouteOptions } from './routes/redirect.js';
36
41
  export { redirectRoutes, linkRoutes, analyticsRoutes, sdkRoutes, webhookRoutes, templateRoutes, qrRoutes, previewRoutes, debugRoutes, wellKnownRoutes, healthRoutes } from './routes/index.js';
37
42
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGnD,OAAO,EAAsB,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAWxE;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,KAAK,CAAC,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oJAAoJ;IACpJ,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,aAAkB,kTAiC7D;AAGD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGnD,OAAO,EAAsB,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAkB,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAUjF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,KAAK,CAAC,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oJAAoJ;IACpJ,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,oBAAoB,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,aAAkB,kTAiC7D;AAGD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ export async function createServer(options = {}) {
40
40
  // Routes
41
41
  await fastify.register(healthRoutes);
42
42
  await fastify.register(wellKnownRoutes);
43
- await fastify.register(redirectRoutes);
43
+ await fastify.register(redirectRoutes, options.redirect ?? {});
44
44
  await fastify.register(linkRoutes);
45
45
  await fastify.register(analyticsRoutes);
46
46
  await fastify.register(sdkRoutes);
@@ -56,6 +56,7 @@ export * from './lib/database.js';
56
56
  export * from './lib/fingerprint.js';
57
57
  export * from './lib/webhook.js';
58
58
  export * from './lib/link-safety.js';
59
+ export * from './lib/launchpad.js';
59
60
  export * from './lib/event-emitter.js';
60
61
  export * from './types/index.js';
61
62
  export { redirectRoutes, linkRoutes, analyticsRoutes, sdkRoutes, webhookRoutes, templateRoutes, qrRoutes, previewRoutes, debugRoutes, wellKnownRoutes, healthRoutes } from './routes/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAA4B,MAAM,SAAS,CAAC;AACnD,OAAO,IAAI,MAAM,eAAe,CAAC;AACjC,OAAO,KAAK,MAAM,gBAAgB,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAmB,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAkBlD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAyB,EAAE;IAC5D,MAAM,OAAO,GAAG,OAAO,CAAC;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;QAC5D,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC,CAAC;IAEH,OAAO;IACP,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;QAC3B,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG;KACpC,CAAC,CAAC;IAEH,mBAAmB;IACnB,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE;YAC5B,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG;SACvB,CAAC,CAAC;IACL,CAAC;IAED,WAAW;IACX,MAAM,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3C,SAAS;IACT,MAAM,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACxC,MAAM,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACnC,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACxC,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtC,MAAM,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEjC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gCAAgC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAA4B,MAAM,SAAS,CAAC;AACnD,OAAO,IAAI,MAAM,eAAe,CAAC;AACjC,OAAO,KAAK,MAAM,gBAAgB,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAmB,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,cAAc,EAA6B,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAoBlD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAyB,EAAE;IAC5D,MAAM,OAAO,GAAG,OAAO,CAAC;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;QAC5D,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC,CAAC;IAEH,OAAO;IACP,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;QAC3B,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG;KACpC,CAAC,CAAC;IAEH,mBAAmB;IACnB,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE;YAC5B,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG;SACvB,CAAC,CAAC;IACL,CAAC;IAED,WAAW;IACX,MAAM,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3C,SAAS;IACT,MAAM,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACxC,MAAM,OAAO,CAAC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC/D,MAAM,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACnC,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACxC,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtC,MAAM,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEjC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gCAAgC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,eAAO,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;AA4BvB;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAG5C,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,eAAoB,iBAmnBrE"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,eAAO,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;AA4BvB;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAG5C,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,eAAoB,iBAuoBrE"}
@@ -335,6 +335,25 @@ export async function initializeDatabase(options = {}) {
335
335
  ALTER TABLE links ADD COLUMN og_image_url TEXT;
336
336
  END IF;
337
337
  END $$;
338
+ `);
339
+ // Per-link override for the launchpad page (see lib/launchpad.ts):
340
+ // inherit — follow the workspace setting (the default)
341
+ // on — serve the page to desktop visitors even when the link has a
342
+ // web destination
343
+ // off — never serve it; a link with no web destination gets the plain
344
+ // "opens in an app" page instead
345
+ // NOT NULL with a default, so a cached row from before the column existed
346
+ // and a freshly inserted row read the same way.
347
+ await client.query(`
348
+ DO $$
349
+ BEGIN
350
+ IF NOT EXISTS (
351
+ SELECT 1 FROM information_schema.columns
352
+ WHERE table_name='links' AND column_name='launchpad_mode'
353
+ ) THEN
354
+ ALTER TABLE links ADD COLUMN launchpad_mode VARCHAR(10) NOT NULL DEFAULT 'inherit';
355
+ END IF;
356
+ END $$;
338
357
  `);
339
358
  await client.query(`
340
359
  DO $$
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AAUpB,MAAM,CAAC,IAAI,EAAW,CAAC;AAEvB,+CAA+C;AAC/C,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,qDAAqD;AACrD,KAAK,UAAU,gBAAgB,CAAC,aAAqB,EAAE,EAAE,YAAoB,IAAI;IAC/E,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;YAC5D,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;gBAC1D,MAAM,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,sBAAsB;gBAC1E,OAAO,CAAC,GAAG,CAAC,+BAA+B,OAAO,wBAAwB,KAAK,OAAO,CAAC,CAAC;gBACxF,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,kDAAkD,EAAE,KAAK,CAAC,CAAC;gBACzE,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAE5C,6BAA6B;AAC7B,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,UAA2B,EAAE;IACpE,kBAAkB;IAClB,EAAE,GAAG,IAAI,IAAI,CAAC;QACZ,gBAAgB,EAAE,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,yDAAyD;QACtH,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK;QAClF,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC;QAC3B,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE;KAC7B,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAExC,oDAAoD;IACpD,EAAE;IACF,0EAA0E;IAC1E,0EAA0E;IAC1E,yDAAyD;IACzD,+EAA+E;IAC/E,6DAA6D;IAC7D,yEAAyE;IACzE,SAAS;IACT,EAAE;IACF,2EAA2E;IAC3E,uEAAuE;IACvE,wEAAwE;IACxE,8EAA8E;IAC9E,qDAAqD;IACrD,EAAE;IACF,2EAA2E;IAC3E,2EAA2E;IAC3E,6EAA6E;IAC7E,uDAAuD;IACvD,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC;QAC1E,QAAQ,GAAG,IAAI,CAAC;QAEhB,2EAA2E;QAC3E,EAAE;QACF,8EAA8E;QAC9E,8EAA8E;QAC9E,8EAA8E;QAC9E,4EAA4E;QAC5E,yDAAyD;QACzD,EAAE;QACF,0EAA0E;QAC1E,+EAA+E;QAC/E,8EAA8E;QAC9E,8BAA8B;QAC9B,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;KASlB,CAAC,CAAC;QAEH,2EAA2E;QAC3E,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;KAYlB,CAAC,CAAC;QAEH,cAAc;QACd,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;KAmBlB,CAAC,CAAC;QAEH,qBAAqB;QACrB,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;KAwBlB,CAAC,CAAC;QAEH,kGAAkG;QAClG,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;KAelB,CAAC,CAAC;QAEH,2FAA2F;QAC3F,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;KAyBlB,CAAC,CAAC;QAEH,kEAAkE;QAClE,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;KASlB,CAAC,CAAC;QAEH,qEAAqE;QACrE,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;KAelB,CAAC,CAAC;QAEH,6CAA6C;QAC7C,EAAE;QACF,0EAA0E;QAC1E,0EAA0E;QAC1E,2EAA2E;QAC3E,iEAAiE;QACjE,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,wCAAwC;QACxC,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,sBAAsB;QACtB,EAAE;QACF,6EAA6E;QAC7E,yCAAyC;QACzC,EAAE;QACF,gFAAgF;QAChF,8EAA8E;QAC9E,8EAA8E;QAC9E,6EAA6E;QAC7E,gEAAgE;QAChE,iEAAiE;QACjE,+EAA+E;QAC/E,EAAE;QACF,2EAA2E;QAC3E,6BAA6B;QAC7B,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;KAsBlB,CAAC,CAAC;QAEH,qEAAqE;QACrE,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,4DAA4D;QAC5D,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,mEAAmE;QACnE,yDAAyD;QACzD,0EAA0E;QAC1E,8BAA8B;QAC9B,4EAA4E;QAC5E,6CAA6C;QAC7C,0EAA0E;QAC1E,gDAAgD;QAChD,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,6EAA6E;QAC7E,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,kDAAkD;QAClD,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;KAalB,CAAC,CAAC;QAEH,0DAA0D;QAC1D,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;KAalB,CAAC,CAAC;QAEH,kFAAkF;QAClF,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,oCAAoC;QACpC,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,kCAAkC;QAClC,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,kDAAkD;QAClD,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,4DAA4D;QAC5D,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,2EAA2E;QAC3E,4EAA4E;QAC5E,yEAAyE;QACzE,4EAA4E;QAC5E,wEAAwE;QACxE,sEAAsE;QACtE,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,4DAA4D;QAC5D,6EAA6E;QAC7E,4EAA4E;QAC5E,2EAA2E;QAC3E,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,iEAAiE;QACjE,wEAAwE;QACxE,0EAA0E;QAC1E,2CAA2C;QAC3C,EAAE;QACF,4EAA4E;QAC5E,sEAAsE;QACtE,4EAA4E;QAC5E,oDAAoD;QACpD,EAAE;QACF,wEAAwE;QACxE,0EAA0E;QAC1E,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;KAOlB,CAAC,CAAC;QAEH,8DAA8D;QAC9D,6EAA6E;QAC7E,8EAA8E;QAC9E,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,mDAAmD;QACnD,6EAA6E;QAC7E,4EAA4E;QAC5E,6EAA6E;QAC7E,wEAAwE;QACxE,+EAA+E;QAC/E,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;KAgBlB,CAAC,CAAC;QAEH,iEAAiE;QACjE,wEAAwE;QACxE,4EAA4E;QAC5E,4EAA4E;QAC5E,8EAA8E;QAC9E,2EAA2E;QAC3E,yEAAyE;QACzE,2EAA2E;QAC3E,oBAAoB;QACpB,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;KAgBlB,CAAC,CAAC;QAEH,iCAAiC;QACjC,MAAM,MAAM,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;QAClG,MAAM,MAAM,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACrF,MAAM,MAAM,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;QAChG,MAAM,MAAM,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;QAC7F,MAAM,MAAM,CAAC,KAAK,CAAC,kFAAkF,CAAC,CAAC;QACvG,MAAM,MAAM,CAAC,KAAK,CAAC,2FAA2F,CAAC,CAAC;QAChH,qFAAqF;QACrF,MAAM,MAAM,CAAC,KAAK,CAAC,sHAAsH,CAAC,CAAC;QAC3I,oCAAoC;QACpC,MAAM,MAAM,CAAC,KAAK,CAAC,2FAA2F,CAAC,CAAC;QAChH,MAAM,MAAM,CAAC,KAAK,CAAC,uFAAuF,CAAC,CAAC;QAC5G,MAAM,MAAM,CAAC,KAAK,CAAC,yFAAyF,CAAC,CAAC;QAC9G,MAAM,MAAM,CAAC,KAAK,CAAC,4EAA4E,CAAC,CAAC;QACjG,MAAM,MAAM,CAAC,KAAK,CAAC,wFAAwF,CAAC,CAAC;QAC7G,MAAM,MAAM,CAAC,KAAK,CAAC,iGAAiG,CAAC,CAAC;QAEtH,6BAA6B;QAC7B,MAAM,MAAM,CAAC,KAAK,CAAC,mFAAmF,CAAC,CAAC;QACxG,MAAM,MAAM,CAAC,KAAK,CAAC,kFAAkF,CAAC,CAAC;QACvG,MAAM,MAAM,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;QAC7F,MAAM,MAAM,CAAC,KAAK,CAAC,gFAAgF,CAAC,CAAC;QAErG,uBAAuB;QACvB,MAAM,MAAM,CAAC,KAAK,CAAC,sEAAsE,CAAC,CAAC;QAC3F,MAAM,MAAM,CAAC,KAAK,CAAC,8FAA8F,CAAC,CAAC;QAEnH,4BAA4B;QAC5B,MAAM,MAAM,CAAC,KAAK,CAAC,sFAAsF,CAAC,CAAC;QAC3G,MAAM,MAAM,CAAC,KAAK,CAAC,gFAAgF,CAAC,CAAC;QACrG,MAAM,MAAM,CAAC,KAAK,CAAC,+FAA+F,CAAC,CAAC;QACpH,iFAAiF;QACjF,MAAM,MAAM,CAAC,KAAK,CAAC,yHAAyH,CAAC,CAAC;QAC9I,+EAA+E;QAC/E,0EAA0E;QAC1E,MAAM,MAAM,CAAC,KAAK,CAAC,gHAAgH,CAAC,CAAC;QAErI,kEAAkE;QAClE,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;KAUlB,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QACrD,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,IAAI,QAAQ,EAAE,CAAC;YACb,qEAAqE;YACrE,8DAA8D;YAC9D,MAAM,MAAM;iBACT,KAAK,CAAC,+BAA+B,EAAE,CAAC,oBAAoB,CAAC,CAAC;iBAC9D,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Launchpad: the page a visitor sees when a link cannot open the app.
3
+ *
4
+ * A short link to app-only content has nowhere good to send a desktop visitor,
5
+ * and a phone without the app installed otherwise gets a bare store redirect.
6
+ * This page is the alternative: the link's title, description and image, the
7
+ * app's icon and name, store buttons, a QR code so a desktop visitor can finish
8
+ * on their phone, and — when the app has a URI scheme — an "Open in app" button.
9
+ *
10
+ * Three rules shape everything below:
11
+ *
12
+ * 1. **Never add a hop to a link that already works.** The page is served by
13
+ * default only when a link has no web destination at any level. Serving it
14
+ * in front of a working destination is a per-workspace or per-link choice.
15
+ * 2. **Never navigate on the visitor's behalf.** No timers, no automatic scheme
16
+ * attempts. A forced `myapp://` open with the app absent produces an OS error
17
+ * alert and a dead tab; a button the visitor taps produces neither.
18
+ * 3. **Nothing on the page is authored by the visitor's target.** Every value
19
+ * is escaped; the one exception, `heroHtml`, is rendered by the host
20
+ * application from its own templates and is documented as such below.
21
+ *
22
+ * The page is search-engine invisible (`noindex`, and the route sends
23
+ * `X-Robots-Tag` and `Cache-Control: no-store`), because a redirect host that
24
+ * indexes one page per short link is a thin-content spam surface.
25
+ */
26
+ export type LaunchpadDesktopMode = 'no-destination' | 'always' | 'off';
27
+ export type LaunchpadMobileMode = 'store' | 'page';
28
+ export type LaunchpadLinkMode = 'inherit' | 'on' | 'off';
29
+ /**
30
+ * Per-workspace configuration, read from `organizations.settings.launchpad`.
31
+ * Every field is optional; an absent object means "the defaults", which are
32
+ * today's behaviour everywhere except the no-destination desktop case.
33
+ */
34
+ export interface LaunchpadSettings {
35
+ /** When a desktop visitor gets the page. Default `no-destination`. */
36
+ desktop?: LaunchpadDesktopMode;
37
+ /**
38
+ * What a mobile visitor without the app gets. Default `store` (a redirect).
39
+ * Reserved: the mobile routing does not yet read it, so `page` currently
40
+ * behaves as `store`.
41
+ */
42
+ mobile?: LaunchpadMobileMode;
43
+ /** Shown in the page header, and as the `<title>` fallback. */
44
+ appName?: string;
45
+ /** Absolute https URL of the app icon, shown at 64×64. */
46
+ appIconUrl?: string;
47
+ /** `#rrggbb`. Drives the primary button. Anything else is ignored. */
48
+ accentColor?: string;
49
+ /** Opaque to Core: a host application may key its own page templates on it. */
50
+ templateId?: string;
51
+ }
52
+ export interface LaunchpadTheme {
53
+ appName?: string;
54
+ appIconUrl?: string;
55
+ accentColor?: string;
56
+ }
57
+ /**
58
+ * What the page shows. Produced by `defaultLaunchpadContent()` from the link
59
+ * row, or by a host application's `resolveContent` hook when it has richer
60
+ * material (a rendered share card, a template).
61
+ */
62
+ export interface LaunchpadContent {
63
+ title: string;
64
+ description: string;
65
+ /** Hero image, absolute http(s) URL. Also used for `og:image`. */
66
+ imageUrl: string | null;
67
+ /**
68
+ * Pre-rendered HTML for the hero region, inserted **without escaping**.
69
+ *
70
+ * Trust boundary: this must be produced by the host application from its own
71
+ * templates, never from visitor or end-user input. The page's CSP allows no
72
+ * script without the per-response nonce, which the host does not know, so a
73
+ * mistake here cannot execute — but it can still deface. Leave it unset unless
74
+ * you render it yourself.
75
+ */
76
+ heroHtml?: string;
77
+ theme: LaunchpadTheme;
78
+ }
79
+ /** The subset of a `links` row the default content is built from. */
80
+ export interface LaunchpadLinkFields {
81
+ title?: string | null;
82
+ description?: string | null;
83
+ og_title?: string | null;
84
+ og_description?: string | null;
85
+ og_image_url?: string | null;
86
+ }
87
+ /**
88
+ * Read `settings.launchpad` off a workspace settings JSON blob, tolerating any
89
+ * shape. Settings are written by whatever administers the workspace, not by
90
+ * this package, so nothing here is trusted: unknown modes fall back to the
91
+ * default, a bad colour is dropped, and image URLs must be http(s).
92
+ */
93
+ export declare function readLaunchpadSettings(orgSettings: unknown): LaunchpadSettings;
94
+ /** Normalise `links.launchpad_mode`, which a cached row from before the column existed may lack. */
95
+ export declare function readLaunchpadLinkMode(value: unknown): LaunchpadLinkMode;
96
+ /**
97
+ * Whether a desktop visitor gets the page.
98
+ *
99
+ * The link's own mode wins outright. Otherwise the workspace decides, and the
100
+ * default serves the page only where the alternative is nothing at all.
101
+ */
102
+ export declare function shouldServeLaunchpadOnDesktop(input: {
103
+ hasWebDestination: boolean;
104
+ orgMode?: LaunchpadDesktopMode;
105
+ linkMode?: LaunchpadLinkMode;
106
+ }): boolean;
107
+ /** Content from the link row alone: what any deployment can show with no extra machinery. */
108
+ export declare function defaultLaunchpadContent(link: LaunchpadLinkFields, settings: LaunchpadSettings): LaunchpadContent;
109
+ /** A fresh CSP nonce per response. */
110
+ export declare function createLaunchpadNonce(): string;
111
+ /**
112
+ * The page's content-security policy.
113
+ *
114
+ * Scripts run only with this response's nonce. Inline `style` attributes are
115
+ * allowed because a host-rendered hero region carries them, and a nonce on
116
+ * `style-src` would make browsers ignore `'unsafe-inline'` — so the nonce
117
+ * guards scripts alone. `connect-src` admits the beacon endpoint's origin when
118
+ * one is configured; `sendBeacon` is governed by it.
119
+ */
120
+ export declare function launchpadContentSecurityPolicy(nonce: string, beaconUrl?: string): string;
121
+ export interface LaunchpadPageContext {
122
+ content: LaunchpadContent;
123
+ /** The link's id; the QR code is fetched from `/api/links/{id}/qr`. */
124
+ linkId: string;
125
+ /** Absolute URL of this page, for `og:url`. */
126
+ pageUrl: string;
127
+ iosUrl: string | null;
128
+ androidUrl: string | null;
129
+ /**
130
+ * The app's URI-scheme URL for this link, or null. When set, an "Open in app"
131
+ * button is rendered whose only job is to navigate to it on tap. The URL
132
+ * fragment of the page is appended on tap, so a key that lives only in the
133
+ * fragment survives without ever reaching the server.
134
+ */
135
+ schemeUrl: string | null;
136
+ /** Show the QR block. Meant for desktop; a phone scanning itself is no use. */
137
+ showQr: boolean;
138
+ nonce: string;
139
+ /**
140
+ * When set, the page reports `view` on load and `cta_ios` / `cta_android` /
141
+ * `cta_open` on the matching tap via `navigator.sendBeacon`, as a JSON body
142
+ * `{ linkId, event }`. No cookies, no identifiers. Absent by default; the
143
+ * endpoint is the host application's to provide.
144
+ */
145
+ beaconUrl?: string;
146
+ }
147
+ /**
148
+ * Render the full HTML document. Pure: same context, same output (the nonce
149
+ * is an input). Every string from `content`, the URLs and the theme is
150
+ * escaped; `content.heroHtml` is the documented exception.
151
+ */
152
+ export declare function renderLaunchpadPage(ctx: LaunchpadPageContext): string;
153
+ //# sourceMappingURL=launchpad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchpad.d.ts","sourceRoot":"","sources":["../../src/lib/launchpad.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,237 @@
1
+ import { randomBytes } from 'crypto';
2
+ import { escapeHtml, safeHref } from './link-safety.js';
3
+ const DESKTOP_MODES = ['no-destination', 'always', 'off'];
4
+ const MOBILE_MODES = ['store', 'page'];
5
+ const LINK_MODES = ['inherit', 'on', 'off'];
6
+ const HEX_COLOR = /^#[0-9a-f]{6}$/i;
7
+ const asString = (v, max) => typeof v === 'string' && v.trim() ? v.trim().slice(0, max) : undefined;
8
+ /**
9
+ * Read `settings.launchpad` off a workspace settings JSON blob, tolerating any
10
+ * shape. Settings are written by whatever administers the workspace, not by
11
+ * this package, so nothing here is trusted: unknown modes fall back to the
12
+ * default, a bad colour is dropped, and image URLs must be http(s).
13
+ */
14
+ export function readLaunchpadSettings(orgSettings) {
15
+ const raw = orgSettings && typeof orgSettings === 'object' && orgSettings.launchpad;
16
+ if (!raw || typeof raw !== 'object')
17
+ return {};
18
+ const r = raw;
19
+ const desktop = DESKTOP_MODES.find((m) => m === r.desktop);
20
+ const mobile = MOBILE_MODES.find((m) => m === r.mobile);
21
+ const accentColor = asString(r.accentColor, 7);
22
+ const appIconUrl = asString(r.appIconUrl, 2048);
23
+ return {
24
+ ...(desktop ? { desktop } : {}),
25
+ ...(mobile ? { mobile } : {}),
26
+ ...(asString(r.appName, 60) ? { appName: asString(r.appName, 60) } : {}),
27
+ ...(appIconUrl && safeHref(appIconUrl) ? { appIconUrl } : {}),
28
+ ...(accentColor && HEX_COLOR.test(accentColor) ? { accentColor } : {}),
29
+ ...(asString(r.templateId, 64) ? { templateId: asString(r.templateId, 64) } : {}),
30
+ };
31
+ }
32
+ /** Normalise `links.launchpad_mode`, which a cached row from before the column existed may lack. */
33
+ export function readLaunchpadLinkMode(value) {
34
+ return LINK_MODES.find((m) => m === value) ?? 'inherit';
35
+ }
36
+ /**
37
+ * Whether a desktop visitor gets the page.
38
+ *
39
+ * The link's own mode wins outright. Otherwise the workspace decides, and the
40
+ * default serves the page only where the alternative is nothing at all.
41
+ */
42
+ export function shouldServeLaunchpadOnDesktop(input) {
43
+ const linkMode = input.linkMode ?? 'inherit';
44
+ if (linkMode === 'off')
45
+ return false;
46
+ if (linkMode === 'on')
47
+ return true;
48
+ switch (input.orgMode ?? 'no-destination') {
49
+ case 'always':
50
+ return true;
51
+ case 'off':
52
+ return false;
53
+ default:
54
+ return !input.hasWebDestination;
55
+ }
56
+ }
57
+ /** Content from the link row alone: what any deployment can show with no extra machinery. */
58
+ export function defaultLaunchpadContent(link, settings) {
59
+ const image = link.og_image_url && safeHref(link.og_image_url) ? link.og_image_url : null;
60
+ return {
61
+ title: link.og_title || link.title || settings.appName || 'Open in the app',
62
+ description: link.og_description || link.description || '',
63
+ imageUrl: image,
64
+ theme: {
65
+ ...(settings.appName ? { appName: settings.appName } : {}),
66
+ ...(settings.appIconUrl ? { appIconUrl: settings.appIconUrl } : {}),
67
+ ...(settings.accentColor ? { accentColor: settings.accentColor } : {}),
68
+ },
69
+ };
70
+ }
71
+ /** WCAG relative luminance above ~0.5 reads better with dark text on it. */
72
+ function isLightColor(hex) {
73
+ const channel = (i) => {
74
+ const c = parseInt(hex.slice(i, i + 2), 16) / 255;
75
+ return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
76
+ };
77
+ return 0.2126 * channel(1) + 0.7152 * channel(3) + 0.0722 * channel(5) > 0.5;
78
+ }
79
+ /** A fresh CSP nonce per response. */
80
+ export function createLaunchpadNonce() {
81
+ return randomBytes(16).toString('base64');
82
+ }
83
+ /**
84
+ * The page's content-security policy.
85
+ *
86
+ * Scripts run only with this response's nonce. Inline `style` attributes are
87
+ * allowed because a host-rendered hero region carries them, and a nonce on
88
+ * `style-src` would make browsers ignore `'unsafe-inline'` — so the nonce
89
+ * guards scripts alone. `connect-src` admits the beacon endpoint's origin when
90
+ * one is configured; `sendBeacon` is governed by it.
91
+ */
92
+ export function launchpadContentSecurityPolicy(nonce, beaconUrl) {
93
+ const connect = new Set(["'self'"]);
94
+ if (beaconUrl) {
95
+ try {
96
+ connect.add(new URL(beaconUrl).origin);
97
+ }
98
+ catch {
99
+ // Relative beacon URL — 'self' covers it.
100
+ }
101
+ }
102
+ return [
103
+ "default-src 'none'",
104
+ "img-src 'self' https: data:",
105
+ "style-src 'unsafe-inline'",
106
+ `script-src 'nonce-${nonce}'`,
107
+ `connect-src ${[...connect].join(' ')}`,
108
+ "base-uri 'none'",
109
+ "form-action 'none'",
110
+ ].join('; ');
111
+ }
112
+ const STYLES = `
113
+ :root { --lp-ink: #16181d; --lp-muted: #5f6673; --lp-bg: #ffffff; --lp-surface: #f4f5f7; --lp-line: #e2e5ea; --lp-accent: #2563eb; --lp-accent-ink: #ffffff; }
114
+ @media (prefers-color-scheme: dark) { :root { --lp-ink: #eef0f3; --lp-muted: #a3abb8; --lp-bg: #121418; --lp-surface: #1c1f25; --lp-line: #2b3038; } }
115
+ * { box-sizing: border-box; }
116
+ body { margin: 0; background: var(--lp-bg); color: var(--lp-ink); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; line-height: 1.5; -webkit-font-smoothing: antialiased; }
117
+ .lp { max-width: 40rem; margin: 0 auto; padding: 2rem 1.25rem 3rem; display: flex; flex-direction: column; gap: 1.5rem; }
118
+ .lp-app { display: flex; align-items: center; gap: 0.75rem; min-height: 1rem; }
119
+ .lp-app img { width: 48px; height: 48px; border-radius: 12px; object-fit: cover; background: var(--lp-surface); }
120
+ .lp-app span { font-weight: 600; font-size: 1rem; }
121
+ .lp-hero img { display: block; width: 100%; max-height: 22rem; object-fit: cover; border-radius: 14px; background: var(--lp-surface); margin-bottom: 1rem; }
122
+ .lp-hero h1 { font-size: 1.75rem; line-height: 1.2; margin: 0 0 0.5rem; text-wrap: balance; }
123
+ .lp-hero p { margin: 0; color: var(--lp-muted); font-size: 1.05rem; }
124
+ .lp-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; }
125
+ .lp-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; padding: 0.8rem 1.25rem; border-radius: 10px; font-size: 0.95rem; font-weight: 600; text-decoration: none; border: 1px solid var(--lp-line); background: var(--lp-surface); color: var(--lp-ink); }
126
+ .lp-btn-primary { background: var(--lp-accent); border-color: var(--lp-accent); color: var(--lp-accent-ink); }
127
+ .lp-btn:focus-visible { outline: 2px solid var(--lp-accent); outline-offset: 2px; }
128
+ .lp-qr { display: flex; align-items: center; gap: 1.25rem; padding: 1rem; border: 1px solid var(--lp-line); border-radius: 14px; background: var(--lp-surface); }
129
+ .lp-qr img { width: 132px; height: 132px; border-radius: 8px; background: #fff; flex: none; }
130
+ .lp-qr strong { display: block; font-size: 1rem; margin-bottom: 0.2rem; }
131
+ .lp-qr p { margin: 0; color: var(--lp-muted); font-size: 0.9rem; }
132
+ @media (max-width: 480px) { .lp-qr { flex-direction: column; text-align: center; } .lp-hero h1 { font-size: 1.5rem; } }
133
+ `;
134
+ /** Only shipped when a button or a beacon needs it; a page with neither has no script at all. */
135
+ const SCRIPT = `
136
+ (function () {
137
+ var body = document.body;
138
+ var open = document.getElementById('lp-open');
139
+ if (open) {
140
+ open.addEventListener('click', function () {
141
+ open.href = open.getAttribute('data-scheme') + (window.location.hash || '');
142
+ });
143
+ }
144
+ var beacon = body.getAttribute('data-beacon');
145
+ if (beacon && navigator.sendBeacon) {
146
+ var linkId = body.getAttribute('data-link-id');
147
+ var send = function (event) {
148
+ try { navigator.sendBeacon(beacon, JSON.stringify({ linkId: linkId, event: event })); } catch (e) {}
149
+ };
150
+ send('view');
151
+ var ctas = document.querySelectorAll('[data-lp-cta]');
152
+ for (var i = 0; i < ctas.length; i++) {
153
+ ctas[i].addEventListener('click', function (e) { send(e.currentTarget.getAttribute('data-lp-cta')); });
154
+ }
155
+ }
156
+ })();
157
+ `;
158
+ /**
159
+ * Render the full HTML document. Pure: same context, same output (the nonce
160
+ * is an input). Every string from `content`, the URLs and the theme is
161
+ * escaped; `content.heroHtml` is the documented exception.
162
+ */
163
+ export function renderLaunchpadPage(ctx) {
164
+ const content = ctx.content;
165
+ const theme = content.theme;
166
+ const title = escapeHtml(content.title);
167
+ const description = escapeHtml(content.description);
168
+ const imageUrl = content.imageUrl && safeHref(content.imageUrl) ? escapeHtml(content.imageUrl) : null;
169
+ const iconUrl = theme.appIconUrl && safeHref(theme.appIconUrl) ? escapeHtml(theme.appIconUrl) : null;
170
+ const iosUrl = ctx.iosUrl && safeHref(ctx.iosUrl) ? escapeHtml(ctx.iosUrl) : null;
171
+ const androidUrl = ctx.androidUrl && safeHref(ctx.androidUrl) ? escapeHtml(ctx.androidUrl) : null;
172
+ const accent = theme.accentColor && HEX_COLOR.test(theme.accentColor) ? theme.accentColor : null;
173
+ const accentInk = accent && isLightColor(accent) ? '#16181d' : '#ffffff';
174
+ const nonce = escapeHtml(ctx.nonce);
175
+ const head = [
176
+ `<title>${title}</title>`,
177
+ description ? `<meta name="description" content="${description}">` : '',
178
+ `<meta property="og:type" content="website">`,
179
+ `<meta property="og:url" content="${escapeHtml(ctx.pageUrl)}">`,
180
+ `<meta property="og:title" content="${title}">`,
181
+ description ? `<meta property="og:description" content="${description}">` : '',
182
+ imageUrl ? `<meta property="og:image" content="${imageUrl}">` : '',
183
+ `<meta name="twitter:card" content="${imageUrl ? 'summary_large_image' : 'summary'}">`,
184
+ ]
185
+ .filter(Boolean)
186
+ .join('\n');
187
+ const header = iconUrl || theme.appName
188
+ ? `<header class="lp-app">${iconUrl ? `<img src="${iconUrl}" alt="" width="48" height="48">` : ''}${theme.appName ? `<span>${escapeHtml(theme.appName)}</span>` : ''}</header>`
189
+ : '';
190
+ const hero = content.heroHtml
191
+ ? `<section class="lp-hero">${content.heroHtml}</section>`
192
+ : `<section class="lp-hero">${imageUrl ? `<img src="${imageUrl}" alt="">` : ''}<h1>${title}</h1>${description ? `<p>${description}</p>` : ''}</section>`;
193
+ const buttons = [
194
+ ctx.schemeUrl
195
+ ? `<a class="lp-btn lp-btn-primary" id="lp-open" data-lp-cta="cta_open" data-scheme="${escapeHtml(ctx.schemeUrl)}" href="${escapeHtml(ctx.schemeUrl)}">Open in app</a>`
196
+ : '',
197
+ iosUrl
198
+ ? `<a class="lp-btn${ctx.schemeUrl ? '' : ' lp-btn-primary'}" data-lp-cta="cta_ios" href="${iosUrl}">Download on the App Store</a>`
199
+ : '',
200
+ androidUrl
201
+ ? `<a class="lp-btn${ctx.schemeUrl || iosUrl ? '' : ' lp-btn-primary'}" data-lp-cta="cta_android" href="${androidUrl}">Get it on Google Play</a>`
202
+ : '',
203
+ ]
204
+ .filter(Boolean)
205
+ .join('');
206
+ const actions = buttons ? `<section class="lp-actions">${buttons}</section>` : '';
207
+ const qr = ctx.showQr
208
+ ? `<section class="lp-qr"><img src="/api/links/${escapeHtml(ctx.linkId)}/qr?format=svg&amp;size=264" alt="QR code for this link" width="132" height="132"><div><strong>Scan to open on your phone</strong><p>Point your phone's camera at the code to open this link there.</p></div></section>`
209
+ : '';
210
+ const needsScript = Boolean(ctx.schemeUrl || ctx.beaconUrl);
211
+ const bodyAttrs = [
212
+ `data-link-id="${escapeHtml(ctx.linkId)}"`,
213
+ ctx.beaconUrl ? `data-beacon="${escapeHtml(ctx.beaconUrl)}"` : '',
214
+ ]
215
+ .filter(Boolean)
216
+ .join(' ');
217
+ return `<!DOCTYPE html>
218
+ <html lang="en">
219
+ <head>
220
+ <meta charset="utf-8">
221
+ <meta name="viewport" content="width=device-width, initial-scale=1">
222
+ <meta name="robots" content="noindex, nofollow">
223
+ ${head}
224
+ <style>${STYLES}${accent ? `\n :root { --lp-accent: ${accent}; --lp-accent-ink: ${accentInk}; }` : ''}</style>
225
+ </head>
226
+ <body ${bodyAttrs}>
227
+ <main class="lp">
228
+ ${header}
229
+ ${hero}
230
+ ${actions}
231
+ ${qr}
232
+ </main>
233
+ ${needsScript ? `<script nonce="${nonce}">${SCRIPT}</script>` : ''}
234
+ </body>
235
+ </html>`;
236
+ }
237
+ //# sourceMappingURL=launchpad.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchpad.js","sourceRoot":"","sources":["../../src/lib/launchpad.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=launchpad.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchpad.test.d.ts","sourceRoot":"","sources":["../../src/lib/launchpad.test.ts"],"names":[],"mappings":""}