@drawnagency/primitives 0.1.52 → 0.1.54

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.
@@ -2,7 +2,10 @@ import type { Session, CookieLike } from "./types";
2
2
  export declare const SESSION_COOKIE = "bp-session";
3
3
  export declare const AUDIENCE_COOKIE = "bp-audience";
4
4
  export declare const SESSION_MAX_AGE_SECONDS: number;
5
+ export declare const AUDIENCE_MAX_AGE_SECONDS: number;
5
6
  export declare function signSessionToken(session: Session): Promise<string>;
6
7
  export declare function verifySessionToken(token: string): Promise<Session | null>;
8
+ export declare function signAudienceToken(audience: string): Promise<string>;
9
+ export declare function verifyAudienceToken(token: string): Promise<string | null>;
7
10
  export declare function setSessionCookie(cookies: CookieLike, token: string, isProduction: boolean): void;
8
11
  //# sourceMappingURL=cookies.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/auth/cookies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGnD,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,uBAAuB,QAAe,CAAC;AAEpD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAWxE;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAe/E;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,OAAO,GACpB,IAAI,CAQN"}
1
+ {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/auth/cookies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGnD,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,uBAAuB,QAAe,CAAC;AACpD,eAAO,MAAM,wBAAwB,QAAoB,CAAC;AAE1D,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAWxE;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAe/E;AAMD,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMzE;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS/E;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,OAAO,GACpB,IAAI,CAQN"}
@@ -1,5 +1,5 @@
1
1
  export type { Role, Session, SiteUser, Audience, SignInMethod, SignInResult, TokenExchangeType, TokenExchangeResult, AuthProvider, CookieLike, AuthContext, } from "./types";
2
2
  export { requireSessionSecret, isSameOriginRequest, safeNextPath } from "./security";
3
- export { signSessionToken, verifySessionToken, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS } from "./cookies";
3
+ export { signSessionToken, verifySessionToken, signAudienceToken, verifyAudienceToken, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS, AUDIENCE_MAX_AGE_SECONDS } from "./cookies";
4
4
  export { LastOwnerError } from "./errors";
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAC7I,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAC/M,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
@@ -1,12 +1,15 @@
1
1
  import {
2
2
  AUDIENCE_COOKIE,
3
+ AUDIENCE_MAX_AGE_SECONDS,
3
4
  LastOwnerError,
4
5
  SESSION_COOKIE,
5
6
  SESSION_MAX_AGE_SECONDS,
6
7
  setSessionCookie,
8
+ signAudienceToken,
7
9
  signSessionToken,
10
+ verifyAudienceToken,
8
11
  verifySessionToken
9
- } from "../chunk-YEOGH3QH.js";
12
+ } from "../chunk-PIKI3HUP.js";
10
13
  import {
11
14
  isSameOriginRequest,
12
15
  requireSessionSecret,
@@ -15,6 +18,7 @@ import {
15
18
  import "../chunk-WKZ7OENC.js";
16
19
  export {
17
20
  AUDIENCE_COOKIE,
21
+ AUDIENCE_MAX_AGE_SECONDS,
18
22
  LastOwnerError,
19
23
  SESSION_COOKIE,
20
24
  SESSION_MAX_AGE_SECONDS,
@@ -22,6 +26,8 @@ export {
22
26
  requireSessionSecret,
23
27
  safeNextPath,
24
28
  setSessionCookie,
29
+ signAudienceToken,
25
30
  signSessionToken,
31
+ verifyAudienceToken,
26
32
  verifySessionToken
27
33
  };
@@ -7,6 +7,7 @@ import * as jose from "jose";
7
7
  var SESSION_COOKIE = "bp-session";
8
8
  var AUDIENCE_COOKIE = "bp-audience";
9
9
  var SESSION_MAX_AGE_SECONDS = 60 * 60 * 24;
10
+ var AUDIENCE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
10
11
  async function signSessionToken(session) {
11
12
  return new jose.SignJWT({
12
13
  userId: session.userId,
@@ -31,6 +32,19 @@ async function verifySessionToken(token) {
31
32
  return null;
32
33
  }
33
34
  }
35
+ async function signAudienceToken(audience) {
36
+ return new jose.SignJWT({ audience }).setProtectedHeader({ alg: "HS256" }).setExpirationTime(`${AUDIENCE_MAX_AGE_SECONDS}s`).setIssuedAt().sign(requireSessionSecret());
37
+ }
38
+ async function verifyAudienceToken(token) {
39
+ const secret = requireSessionSecret();
40
+ try {
41
+ const { payload } = await jose.jwtVerify(token, secret);
42
+ const audience = payload.audience;
43
+ return typeof audience === "string" && audience !== "" ? audience : null;
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
34
48
  function setSessionCookie(cookies, token, isProduction) {
35
49
  cookies.set(SESSION_COOKIE, token, {
36
50
  httpOnly: true,
@@ -53,8 +67,11 @@ export {
53
67
  SESSION_COOKIE,
54
68
  AUDIENCE_COOKIE,
55
69
  SESSION_MAX_AGE_SECONDS,
70
+ AUDIENCE_MAX_AGE_SECONDS,
56
71
  signSessionToken,
57
72
  verifySessionToken,
73
+ signAudienceToken,
74
+ verifyAudienceToken,
58
75
  setSessionCookie,
59
76
  LastOwnerError
60
77
  };
@@ -1 +1 @@
1
- {"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAgEjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,GACZ,EAAE,KAAK,2CA22BP"}
1
+ {"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAgEjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;CACjE;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,GACZ,EAAE,KAAK,2CA22BP"}
package/dist/index.js CHANGED
@@ -61,13 +61,16 @@ import {
61
61
  } from "./chunk-24SUF2BC.js";
62
62
  import {
63
63
  AUDIENCE_COOKIE,
64
+ AUDIENCE_MAX_AGE_SECONDS,
64
65
  LastOwnerError,
65
66
  SESSION_COOKIE,
66
67
  SESSION_MAX_AGE_SECONDS,
67
68
  setSessionCookie,
69
+ signAudienceToken,
68
70
  signSessionToken,
71
+ verifyAudienceToken,
69
72
  verifySessionToken
70
- } from "./chunk-YEOGH3QH.js";
73
+ } from "./chunk-PIKI3HUP.js";
71
74
  import {
72
75
  isSameOriginRequest,
73
76
  requireSessionSecret,
@@ -100,6 +103,7 @@ import {
100
103
  } from "./chunk-DKOUFIP6.js";
101
104
  export {
102
105
  AUDIENCE_COOKIE,
106
+ AUDIENCE_MAX_AGE_SECONDS,
103
107
  AudienceColorSchema,
104
108
  AudienceNameSchema,
105
109
  AudienceSchema,
@@ -177,8 +181,10 @@ export {
177
181
  sanitizeMediaName,
178
182
  setMediaProvider,
179
183
  setSessionCookie,
184
+ signAudienceToken,
180
185
  signSessionToken,
181
186
  slugifyAudienceName,
182
187
  toSectionId,
188
+ verifyAudienceToken,
183
189
  verifySessionToken
184
190
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawnagency/primitives",
3
- "version": "0.1.52",
3
+ "version": "0.1.54",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./package.json": "./package.json",
@@ -56,6 +56,7 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "@atlaskit/pragmatic-drag-and-drop": "^1.7.10",
59
+ "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.5",
59
60
  "@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
60
61
  "@tiptap/core": "^3.20.4",
61
62
  "@tiptap/extension-link": "^3.20.4",
@@ -5,6 +5,7 @@ import { requireSessionSecret } from "./security";
5
5
  export const SESSION_COOKIE = "bp-session";
6
6
  export const AUDIENCE_COOKIE = "bp-audience";
7
7
  export const SESSION_MAX_AGE_SECONDS = 60 * 60 * 24;
8
+ export const AUDIENCE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
8
9
 
9
10
  export async function signSessionToken(session: Session): Promise<string> {
10
11
  return new jose.SignJWT({
@@ -36,6 +37,29 @@ export async function verifySessionToken(token: string): Promise<Session | null>
36
37
  }
37
38
  }
38
39
 
40
+ // The audience cookie must be unforgeable: middleware trusts its value to gate
41
+ // viewer content, so it carries a signed JWT, not a plaintext audience name.
42
+ // SESSION_SECRET is generated per-site by the provisioner, so the signature
43
+ // alone also prevents cross-site replay — no siteId claim needed.
44
+ export async function signAudienceToken(audience: string): Promise<string> {
45
+ return new jose.SignJWT({ audience })
46
+ .setProtectedHeader({ alg: "HS256" })
47
+ .setExpirationTime(`${AUDIENCE_MAX_AGE_SECONDS}s`)
48
+ .setIssuedAt()
49
+ .sign(requireSessionSecret());
50
+ }
51
+
52
+ export async function verifyAudienceToken(token: string): Promise<string | null> {
53
+ const secret = requireSessionSecret(); // throws on misconfiguration, before try
54
+ try {
55
+ const { payload } = await jose.jwtVerify(token, secret);
56
+ const audience = payload.audience;
57
+ return typeof audience === "string" && audience !== "" ? audience : null;
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
39
63
  export function setSessionCookie(
40
64
  cookies: CookieLike,
41
65
  token: string,
package/src/auth/index.ts CHANGED
@@ -13,5 +13,5 @@ export type {
13
13
  } from "./types";
14
14
 
15
15
  export { requireSessionSecret, isSameOriginRequest, safeNextPath } from "./security";
16
- export { signSessionToken, verifySessionToken, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS } from "./cookies";
16
+ export { signSessionToken, verifySessionToken, signAudienceToken, verifyAudienceToken, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS, AUDIENCE_MAX_AGE_SECONDS } from "./cookies";
17
17
  export { LastOwnerError } from "./errors";
@@ -1,6 +1,8 @@
1
1
  import { Fragment, useState, useCallback, useEffect, useRef, useMemo, type ReactNode } from "react";
2
2
 
3
3
  import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
4
+ import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
5
+ import { autoScrollWindowForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
4
6
  import type { LoadedSection } from "../../lib/loader";
5
7
  import type { SectionContent } from "../../schemas/sections";
6
8
  import type { SiteIndex, SiteConfig, Page } from "../../schemas/site-config";
@@ -1151,13 +1153,20 @@ function EditorContent({
1151
1153
  : sections;
1152
1154
 
1153
1155
  useEffect(() => {
1154
- return monitorForElements({
1155
- onDragStart: ({ source }) => {
1156
- if (source.data.dragType === "section") {
1157
- setPendingInsertIndex(null);
1158
- }
1159
- },
1160
- });
1156
+ return combine(
1157
+ monitorForElements({
1158
+ onDragStart: ({ source }) => {
1159
+ if (source.data.dragType === "section") {
1160
+ setPendingInsertIndex(null);
1161
+ }
1162
+ },
1163
+ }),
1164
+ // Gradually scroll the window when a section drag nears the viewport
1165
+ // edge, so long reorders don't require repeated drag-and-release
1166
+ autoScrollWindowForElements({
1167
+ canScroll: ({ source }) => source.data.dragType === "section",
1168
+ }),
1169
+ );
1161
1170
  }, []);
1162
1171
 
1163
1172
  return (