@kywi-software/core 0.6.0 → 0.6.2
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 +44 -0
- package/dist/admin/app.d.ts.map +1 -1
- package/dist/admin/app.js.map +1 -1
- package/dist/admin/registry.d.ts +6 -6
- package/dist/admin/registry.d.ts.map +1 -1
- package/dist/api/audience-runtime-routes.d.ts.map +1 -1
- package/dist/api/audience-runtime-routes.js +6 -2
- package/dist/api/audience-runtime-routes.js.map +1 -1
- package/dist/api/graphql/handler.d.ts +1 -1
- package/dist/api/graphql/handler.d.ts.map +1 -1
- package/dist/api/graphql/handler.js +8 -1
- package/dist/api/graphql/handler.js.map +1 -1
- package/dist/api/graphql/resolvers.d.ts +15 -6
- package/dist/api/graphql/resolvers.d.ts.map +1 -1
- package/dist/api/graphql/resolvers.js +108 -9
- package/dist/api/graphql/resolvers.js.map +1 -1
- package/dist/api/graphql/schema.d.ts +1 -1
- package/dist/api/graphql/schema.d.ts.map +1 -1
- package/dist/api/graphql/schema.js +14 -3
- package/dist/api/graphql/schema.js.map +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +10 -2
- package/dist/api/index.js.map +1 -1
- package/dist/api/search-routes.d.ts.map +1 -1
- package/dist/api/search-routes.js +9 -0
- package/dist/api/search-routes.js.map +1 -1
- package/dist/audiences/collectors/index.d.ts +1 -0
- package/dist/audiences/collectors/index.d.ts.map +1 -1
- package/dist/audiences/collectors/index.js +1 -0
- package/dist/audiences/collectors/index.js.map +1 -1
- package/dist/audiences/collectors/pinned-audience.d.ts +17 -0
- package/dist/audiences/collectors/pinned-audience.d.ts.map +1 -0
- package/dist/audiences/collectors/pinned-audience.js +22 -0
- package/dist/audiences/collectors/pinned-audience.js.map +1 -0
- package/dist/audiences/cookies.d.ts +1 -0
- package/dist/audiences/cookies.d.ts.map +1 -1
- package/dist/audiences/cookies.js +4 -0
- package/dist/audiences/cookies.js.map +1 -1
- package/dist/audiences/engine.d.ts.map +1 -1
- package/dist/audiences/engine.js +10 -2
- package/dist/audiences/engine.js.map +1 -1
- package/dist/audiences/index.d.ts +1 -0
- package/dist/audiences/index.d.ts.map +1 -1
- package/dist/audiences/index.js +4 -0
- package/dist/audiences/index.js.map +1 -1
- package/dist/audiences/utm-persistence.d.ts +46 -0
- package/dist/audiences/utm-persistence.d.ts.map +1 -0
- package/dist/audiences/utm-persistence.js +68 -0
- package/dist/audiences/utm-persistence.js.map +1 -0
- package/dist/db/search-queries.d.ts +7 -0
- package/dist/db/search-queries.d.ts.map +1 -1
- package/dist/db/search-queries.js +3 -0
- package/dist/db/search-queries.js.map +1 -1
- package/dist/experiments/engine.d.ts.map +1 -1
- package/dist/experiments/engine.js +7 -2
- package/dist/experiments/engine.js.map +1 -1
- package/dist/site/styles.css +191 -0
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -70,6 +70,50 @@ export { handler as GET, handler as POST, handler as PATCH, handler as DELETE }
|
|
|
70
70
|
Then `kywi migrate --push && kywi seed` (via `@kywi-software/cli`) applies
|
|
71
71
|
the schema and creates a superadmin user.
|
|
72
72
|
|
|
73
|
+
## GraphQL API (read-only)
|
|
74
|
+
|
|
75
|
+
The same `[...kywi]` catch-all route also mounts a read-only GraphQL
|
|
76
|
+
endpoint at **`POST /api/v1/graphql`** — no separate wiring required. It
|
|
77
|
+
exposes `content(id)`, `contentBySlug(slug, siteId)`,
|
|
78
|
+
`contentList(contentType, siteId, limit, page, status)`,
|
|
79
|
+
`search(query, siteId, contentType, limit)`, `categories(siteId)`,
|
|
80
|
+
`nav(siteId)`, and `media(id)`. There is no mutation type.
|
|
81
|
+
|
|
82
|
+
**Auth.** The endpoint reads the same `Authorization: Bearer <token>` header
|
|
83
|
+
as the REST API. A missing/invalid header resolves to an anonymous caller
|
|
84
|
+
rather than a 401 — anonymous access to published content is legal, matching
|
|
85
|
+
`GET /search?status=published`. Requesting elevated (draft-visible) content —
|
|
86
|
+
an explicit non-published `status`, or omitting `status` on `contentList`,
|
|
87
|
+
`contentBySlug`, or `search` — requires an authenticated caller who is a
|
|
88
|
+
member of the query's `siteId`; otherwise the field returns a GraphQL error
|
|
89
|
+
**before** any row is fetched. `contentBySlug` exposes no `status` arg, so
|
|
90
|
+
every call implicitly requests elevated access and is checked against
|
|
91
|
+
`siteId` membership up front — an authenticated non-member is rejected with
|
|
92
|
+
an error regardless of the row's actual status, since the membership check
|
|
93
|
+
runs before the row is even looked up. Only `content(id)` differs, because
|
|
94
|
+
it takes no `siteId` argument to check membership against up front — it
|
|
95
|
+
fetches the row first and then post-filters: a non-published row resolves
|
|
96
|
+
to `null` for a caller without draft access, rather than erroring.
|
|
97
|
+
|
|
98
|
+
**Per-content-type opt-in (default-deny).** A content type is only
|
|
99
|
+
queryable through GraphQL when its config sets `graphql: true`:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
contentTypes: [
|
|
103
|
+
{ name: 'article', label: 'Article', baseType: 'content', fields: [...], graphql: true },
|
|
104
|
+
{ name: 'internalNote', label: 'Internal Note', baseType: 'content', fields: [...] }, // graphql omitted → denied
|
|
105
|
+
]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Omitting the flag (or setting it `false`) denies GraphQL access to that
|
|
109
|
+
type — this is default-deny, not default-allow. `contentList` for a
|
|
110
|
+
non-opted-in type returns a GraphQL error. `content`/`contentBySlug`
|
|
111
|
+
return `null` when the resolved row's content type isn't opted in.
|
|
112
|
+
`search` rejects an explicit `contentType` argument naming a non-opted-in
|
|
113
|
+
type, and otherwise silently filters results down to opted-in types only.
|
|
114
|
+
`categories`, `nav`, and `media` aren't content-type-scoped, so this flag
|
|
115
|
+
doesn't apply to them.
|
|
116
|
+
|
|
73
117
|
## What's in the package
|
|
74
118
|
|
|
75
119
|
- `.` — DB schema generation, REST API handler, hooks, media, forms,
|
package/dist/admin/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/admin/app.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAA4B,MAAM,OAAO,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,eAAe,CAAA;AAI/D,OAAO,EAAE,aAAa,EAAmB,MAAM,cAAc,CAAA;AAK7D,MAAM,WAAW,iBAAiB;IAChC,sFAAsF;IACtF,OAAO,EAAE,kBAAkB,CAAA;IAC3B,sFAAsF;IACtF,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;;;;OAIG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC,CAAA;IAChF;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,kBAAkB,CAAA;CACtC;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,4CAU9B;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,2CAavE;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/admin/app.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAA4B,MAAM,OAAO,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAgB,MAAM,eAAe,CAAA;AAI/D,OAAO,EAAE,aAAa,EAAmB,MAAM,cAAc,CAAA;AAK7D,MAAM,WAAW,iBAAiB;IAChC,sFAAsF;IACtF,OAAO,EAAE,kBAAkB,CAAA;IAC3B,sFAAsF;IACtF,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;;;;OAIG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;KAAE,CAAC,CAAA;IAChF;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,kBAAkB,CAAA;CACtC;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,4CAU9B;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,2CAavE;AAmDD,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,EAAE,iBAAiB,2CA6B3G;AAKD,OAAO,EAAE,aAAa,EAAE,CAAA"}
|
package/dist/admin/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/admin/app.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAIhD,OAAO,EAAE,UAAU,EAAiB,MAAM,kBAAkB,CAAA;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,YAAY,MAAM,qBAAqB,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAiCzC,6EAA6E;AAC7E,MAAM,UAAU,eAAe;IAC7B,OAAO,CACL,eAAK,SAAS,EAAC,4BAA4B,aACzC,qCAAkB,EAClB,yEAAqD,EACrD,sBACE,YAAG,IAAI,EAAC,QAAQ,8BAAkB,GAChC,IACA,CACP,CAAA;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,EAAE,OAAO,EAA8B;IACtE,OAAO,CACL,eAAK,SAAS,EAAC,4BAA4B,aACzC,iDAAmC,EACnC,+DAEG,OAAO,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,EAAE,SACxD,EACJ,sBACE,YAAG,IAAI,EAAC,QAAQ,8BAAkB,GAChC,IACA,CACP,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,EACnB,OAAO,EACP,MAAM,EACN,OAAO,GAKR;IACC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,eAAe,EAAE,CAAA;IAEzC,yEAAyE;IACzE,4EAA4E;IAC5E,wEAAwE;IACxE,6EAA6E;IAC7E,gBAAgB;IAChB,MAAM,IAAI,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/admin/app.tsx"],"names":[],"mappings":"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"}
|
package/dist/admin/registry.d.ts
CHANGED
|
@@ -70,13 +70,13 @@ export interface AdminSurface {
|
|
|
70
70
|
/**
|
|
71
71
|
* Lazy loader for the surface component.
|
|
72
72
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
73
|
+
* Every surface carries a **static-literal** `import('./surfaces/<area>/<x>.js')`
|
|
74
|
+
* thunk — the literal form (not a dynamically-built path) is what lets
|
|
75
|
+
* webpack/tsc emit one chunk per surface, so each surface's code only loads
|
|
76
|
+
* when that surface is navigated to. The matcher and nav derivation do not
|
|
77
|
+
* depend on `load`; it exists solely to be handed to `React.lazy`.
|
|
78
78
|
*/
|
|
79
|
-
load
|
|
79
|
+
load: () => Promise<{
|
|
80
80
|
default: ComponentType<SurfaceProps>;
|
|
81
81
|
}>;
|
|
82
82
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/admin/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEhD;;;;;;;;GAQG;AAIH;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB,WAAW,GACX,aAAa,GACb,SAAS,GACT,WAAW,GACX,YAAY,GACZ,QAAQ,GACR,OAAO,GACP,OAAO,GACP,OAAO,GACP,UAAU,GACV,OAAO,GACP,UAAU,GACV,cAAc,GACd,OAAO,GACP,WAAW,GACX,aAAa,GACb,SAAS,GACT,YAAY,GACZ,SAAS,GACT,aAAa,GACb,UAAU,GACV,cAAc,CAAA;AAElB,kEAAkE;AAClE,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAuBlC,CAAA;AAIV;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAED,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,EAAE,EAAE,MAAM,CAAA;IACV,oDAAoD;IACpD,IAAI,EAAE,SAAS,CAAA;IACf;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,+FAA+F;IAC/F,GAAG,CAAC,EAAE,eAAe,CAAA;IACrB,gFAAgF;IAChF,OAAO,EAAE,QAAQ,CAAA;IACjB;;;;;;;;OAQG;IACH,IAAI,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/admin/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEhD;;;;;;;;GAQG;AAIH;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB,WAAW,GACX,aAAa,GACb,SAAS,GACT,WAAW,GACX,YAAY,GACZ,QAAQ,GACR,OAAO,GACP,OAAO,GACP,OAAO,GACP,UAAU,GACV,OAAO,GACP,UAAU,GACV,cAAc,GACd,OAAO,GACP,WAAW,GACX,aAAa,GACb,SAAS,GACT,YAAY,GACZ,SAAS,GACT,aAAa,GACb,UAAU,GACV,cAAc,CAAA;AAElB,kEAAkE;AAClE,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAuBlC,CAAA;AAIV;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/B;AAED,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,EAAE,EAAE,MAAM,CAAA;IACV,oDAAoD;IACpD,IAAI,EAAE,SAAS,CAAA;IACf;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,+FAA+F;IAC/F,GAAG,CAAC,EAAE,eAAe,CAAA;IACrB,gFAAgF;IAChF,OAAO,EAAE,QAAQ,CAAA;IACjB;;;;;;;;OAQG;IACH,IAAI,EAAE,MAAM,OAAO,CAAC;QAAE,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;KAAE,CAAC,CAAA;CAC9D;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAA;IACV,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAA;IAC9C,iEAAiE;IACjE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAIvD,eAAO,MAAM,gBAAgB,EAAE,SAAS,aAAa,EAQ3C,CAAA;AAQV,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAwbxC,CAAA;AAEV;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,oBAAoB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audience-runtime-routes.d.ts","sourceRoot":"","sources":["../../src/api/audience-runtime-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAM7C,UAAU,mBAAmB;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;AAEnE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,mBAAmB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"audience-runtime-routes.d.ts","sourceRoot":"","sources":["../../src/api/audience-runtime-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAM7C,UAAU,mBAAmB;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;AAEnE,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,mBAAmB,GAAG,IAAI,CA6C5F"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsonOk, jsonError, unauthorized } from './response.js';
|
|
2
2
|
import { getAudienceById, upsertAdapterIdentity, deleteAdapterIdentity } from '../audiences/queries.js';
|
|
3
3
|
import { verifyHmacSignature } from '../audiences/hmac.js';
|
|
4
|
-
import { COOKIE_NAMES, buildSetCookieHeader } from '../audiences/cookies.js';
|
|
4
|
+
import { COOKIE_NAMES, COOKIE_MAX_AGE, buildSetCookieHeader } from '../audiences/cookies.js';
|
|
5
5
|
export function registerAudienceRuntimeRoutes(router, ctx) {
|
|
6
6
|
const { db, webhookSecret } = ctx;
|
|
7
7
|
// POST /kywi/audience — update kywi_audience cookie
|
|
@@ -12,7 +12,11 @@ export function registerAudienceRuntimeRoutes(router, ctx) {
|
|
|
12
12
|
const audience = await getAudienceById(db, body.audienceId);
|
|
13
13
|
if (!audience || audience.status !== 'active')
|
|
14
14
|
return jsonError('INVALID_AUDIENCE', 'Audience not found or not active', 400);
|
|
15
|
-
|
|
15
|
+
// Persist (not a session cookie) so server-side resolution can read it back
|
|
16
|
+
// on the next render (#85). Non-httpOnly is deliberate: client JS reads and
|
|
17
|
+
// deletes it (opt-out, badge). The read validates the id against the active
|
|
18
|
+
// audiences, so this client-writable value can never force a stale segment.
|
|
19
|
+
const cookie = buildSetCookieHeader(COOKIE_NAMES.AUDIENCE, body.audienceId, COOKIE_MAX_AGE.AUDIENCE, { httpOnly: false });
|
|
16
20
|
return new Response(JSON.stringify({ data: { audienceId: body.audienceId } }), {
|
|
17
21
|
status: 200, headers: { 'Content-Type': 'application/json', 'Set-Cookie': cookie },
|
|
18
22
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audience-runtime-routes.js","sourceRoot":"","sources":["../../src/api/audience-runtime-routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC/D,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AACvG,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"audience-runtime-routes.js","sourceRoot":"","sources":["../../src/api/audience-runtime-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { GraphQLSchema } from 'graphql';
|
|
2
|
-
export declare function handleGraphQLRequest(schema: GraphQLSchema, resolvers: Record<string, Function>, req: Request): Promise<Response>;
|
|
2
|
+
export declare function handleGraphQLRequest(schema: GraphQLSchema, resolvers: Record<string, Function>, req: Request, context?: unknown): Promise<Response>;
|
|
3
3
|
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/graphql/handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EACnC,GAAG,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/api/graphql/handler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EACnC,GAAG,EAAE,OAAO,EAMZ,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,QAAQ,CAAC,CA6CnB"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { graphql, defaultFieldResolver } from 'graphql';
|
|
2
|
-
export async function handleGraphQLRequest(schema, resolvers, req
|
|
2
|
+
export async function handleGraphQLRequest(schema, resolvers, req,
|
|
3
|
+
// Per-request context (the resolved auth user) passed to graphql-js as
|
|
4
|
+
// `contextValue`, reaching every resolver as its third parameter. The route
|
|
5
|
+
// populates it from `resolveAuth`; a missing/invalid Authorization header
|
|
6
|
+
// yields `{ user: null }` (anonymous). Optional so existing callers that pass
|
|
7
|
+
// no context are treated as anonymous — resolvers fail closed on `undefined`.
|
|
8
|
+
context) {
|
|
3
9
|
let body;
|
|
4
10
|
try {
|
|
5
11
|
body = await req.json();
|
|
@@ -15,6 +21,7 @@ export async function handleGraphQLRequest(schema, resolvers, req) {
|
|
|
15
21
|
source: body.query,
|
|
16
22
|
variableValues: body.variables,
|
|
17
23
|
rootValue: resolvers,
|
|
24
|
+
contextValue: context,
|
|
18
25
|
// The Query resolvers live on `rootValue`, keyed by field name, and are
|
|
19
26
|
// written with the standard `(source, args, context, info)` field-resolver
|
|
20
27
|
// signature. graphql-js's default field resolver would instead invoke a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/api/graphql/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAGvD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAqB,EACrB,SAAmC,EACnC,GAAY;
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/api/graphql/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAGvD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAqB,EACrB,SAAmC,EACnC,GAAY;AACZ,uEAAuE;AACvE,4EAA4E;AAC5E,0EAA0E;AAC1E,8EAA8E;AAC9E,8EAA8E;AAC9E,OAAiB;IAEjB,IAAI,IAA6D,CAAA;IACjE,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAA6D,CAAA;IACpF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,EAAE,CAAC,EAC9D,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE,CACjE,CAAA;IACH,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,OAAO,IAAI,QAAQ,CACjB,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,EAAE,CAAC,EAC9D,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE,CACjE,CAAA;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;QAC3B,MAAM;QACN,MAAM,EAAE,IAAI,CAAC,KAAK;QAClB,cAAc,EAAE,IAAI,CAAC,SAAS;QAC9B,SAAS,EAAE,SAAS;QACpB,YAAY,EAAE,OAAO;QACrB,wEAAwE;QACxE,2EAA2E;QAC3E,wEAAwE;QACxE,2EAA2E;QAC3E,yEAAyE;QACzE,6EAA6E;QAC7E,2EAA2E;QAC3E,6EAA6E;QAC7E,aAAa,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;YAC7C,MAAM,IAAI,GAAI,MAAqD,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YACrF,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC/B,OAAQ,IAAqC,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;YAC5E,CAAC;YACD,OAAO,oBAAoB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QAC1D,CAAC;KACF,CAAC,CAAA;IAEF,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE;QAC1C,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;QACjC,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAChD,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -1,26 +1,35 @@
|
|
|
1
1
|
import type { KywiDb } from '../../db/client.js';
|
|
2
|
-
import type { KywiConfig } from '../../config/types.js';
|
|
2
|
+
import type { KywiConfig, UserContext } from '../../config/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Per-request GraphQL context, passed to graphql-js as `contextValue` and
|
|
5
|
+
* reaching resolvers as their third parameter. `user` is the caller resolved
|
|
6
|
+
* from the Authorization header (null = anonymous). Task 2 (#84) builds on this
|
|
7
|
+
* shape — keep it stable.
|
|
8
|
+
*/
|
|
9
|
+
export interface GraphQLContext {
|
|
10
|
+
user: UserContext | null;
|
|
11
|
+
}
|
|
3
12
|
export declare function createResolvers(db: KywiDb, config: KywiConfig): {
|
|
4
13
|
content: (_: unknown, args: {
|
|
5
14
|
id: string;
|
|
6
|
-
}) => Promise<import("../../db/content-queries.js").ContentWithCustomFields | null>;
|
|
15
|
+
}, ctx: GraphQLContext) => Promise<import("../../db/content-queries.js").ContentWithCustomFields | null>;
|
|
7
16
|
contentBySlug: (_: unknown, args: {
|
|
8
17
|
slug: string;
|
|
9
18
|
siteId: string;
|
|
10
|
-
}) => Promise<import("../../db/content-queries.js").ContentWithCustomFields | null>;
|
|
19
|
+
}, ctx: GraphQLContext) => Promise<import("../../db/content-queries.js").ContentWithCustomFields | null>;
|
|
11
20
|
contentList: (_: unknown, args: {
|
|
12
21
|
contentType: string;
|
|
13
22
|
siteId: string;
|
|
14
23
|
limit?: number;
|
|
15
24
|
page?: number;
|
|
16
25
|
status?: string;
|
|
17
|
-
}) => Promise<import("../../db/content-queries.js").ContentWithCustomFields[]>;
|
|
26
|
+
}, ctx: GraphQLContext) => Promise<import("../../db/content-queries.js").ContentWithCustomFields[]>;
|
|
18
27
|
search: (_: unknown, args: {
|
|
19
28
|
query: string;
|
|
20
29
|
siteId: string;
|
|
21
30
|
contentType?: string;
|
|
22
31
|
limit?: number;
|
|
23
|
-
}) => Promise<import("../../db/search-queries.js").SearchResult[]>;
|
|
32
|
+
}, ctx: GraphQLContext) => Promise<import("../../db/search-queries.js").SearchResult[]>;
|
|
24
33
|
categories: (_: unknown, args: {
|
|
25
34
|
siteId: string;
|
|
26
35
|
}) => Promise<{
|
|
@@ -39,7 +48,7 @@ export declare function createResolvers(db: KywiDb, config: KywiConfig): {
|
|
|
39
48
|
}[]>;
|
|
40
49
|
nav: (_: unknown, args: {
|
|
41
50
|
siteId: string;
|
|
42
|
-
}) => Promise<import("../../db/tree-queries.js").NavContentRow[]>;
|
|
51
|
+
}, ctx: GraphQLContext) => Promise<import("../../db/tree-queries.js").NavContentRow[]>;
|
|
43
52
|
media: (_: unknown, args: {
|
|
44
53
|
id: string;
|
|
45
54
|
}) => Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../../../src/api/graphql/resolvers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolvers.d.ts","sourceRoot":"","sources":["../../../src/api/graphql/resolvers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAOpE;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;CACzB;AAqDD,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU;iBAEvC,OAAO,QAAQ;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,OAAO,cAAc;uBAYhE,OAAO,QACJ;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,OACjC,cAAc;qBAUhB,OAAO,QACJ;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,OACxF,cAAc;gBA0BhB,OAAO,QACJ;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,OACxE,cAAc;oBA8BC,OAAO,QAAQ;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;aAGxC,OAAO,QAAQ;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,OAAO,cAAc;eAUpD,OAAO,QAAQ;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;;;;;;;;;EASjD"}
|
|
@@ -1,31 +1,130 @@
|
|
|
1
|
+
import { GraphQLError } from 'graphql';
|
|
1
2
|
import { getContentById, getContentBySlug, listContent } from '../../db/content-queries.js';
|
|
2
3
|
import { searchContent } from '../../db/search-queries.js';
|
|
3
4
|
import { listCategories } from '../../db/category-queries.js';
|
|
4
5
|
import { getNavContentForSite } from '../../db/tree-queries.js';
|
|
6
|
+
import { hasSiteAccess } from '../site-context.js';
|
|
7
|
+
/** True when the caller may see this site's non-published (draft) content. */
|
|
8
|
+
function canSeeDrafts(ctx, siteId) {
|
|
9
|
+
return !!ctx?.user && hasSiteAccess(ctx.user, siteId);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A content type is queryable through GraphQL only when its config explicitly
|
|
13
|
+
* sets `graphql: true` (#84). Absent flag, or `graphql: false`, both mean
|
|
14
|
+
* denied — this is a default-deny gate, not a passthrough.
|
|
15
|
+
*/
|
|
16
|
+
function isGraphQLEnabled(config, contentTypeName) {
|
|
17
|
+
const ct = config.contentTypes.find(c => c.name === contentTypeName);
|
|
18
|
+
return ct?.graphql === true;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Decide the effective status filter for a site-scoped query, mirroring the
|
|
22
|
+
* anonymous-caller rules in `search-routes.ts`:
|
|
23
|
+
* - `status: 'published'` (or any published-only request) is fully public.
|
|
24
|
+
* - Anonymous callers: an absent status silently narrows to 'published'; an
|
|
25
|
+
* EXPLICIT non-published status is a hard denial (GraphQL error), never a
|
|
26
|
+
* silently-swapped result.
|
|
27
|
+
* - Authenticated callers: any elevated (non-published or absent) status is
|
|
28
|
+
* additionally gated on membership of the query's `siteId`.
|
|
29
|
+
*
|
|
30
|
+
* Returns the status to filter by, or `undefined` for "no status filter" (all
|
|
31
|
+
* statuses visible — only reachable by a member requesting elevated access).
|
|
32
|
+
*/
|
|
33
|
+
function resolveStatusFilter(ctx, siteId, requested) {
|
|
34
|
+
// Published-only access is public — no auth required.
|
|
35
|
+
if (requested === 'published')
|
|
36
|
+
return 'published';
|
|
37
|
+
// Elevated (draft-visible) access requested from here on.
|
|
38
|
+
if (!ctx?.user) {
|
|
39
|
+
// Anonymous: an explicit non-published status is unauthorized; an absent
|
|
40
|
+
// status is narrowed to published rather than rejected.
|
|
41
|
+
if (requested !== undefined)
|
|
42
|
+
throw new GraphQLError('Unauthorized');
|
|
43
|
+
return 'published';
|
|
44
|
+
}
|
|
45
|
+
// Authenticated: elevated access requires membership of the target site.
|
|
46
|
+
if (!hasSiteAccess(ctx.user, siteId))
|
|
47
|
+
throw new GraphQLError('Unauthorized');
|
|
48
|
+
// Member: honour the request. `undefined` means no status filter (all rows).
|
|
49
|
+
return requested;
|
|
50
|
+
}
|
|
5
51
|
export function createResolvers(db, config) {
|
|
6
52
|
return {
|
|
7
|
-
content: async (_, args) =>
|
|
8
|
-
|
|
9
|
-
|
|
53
|
+
content: async (_, args, ctx) => {
|
|
54
|
+
// No siteId arg to pre-check against, so fetch then post-check: a
|
|
55
|
+
// non-published row is only visible to a caller with draft access for the
|
|
56
|
+
// row's own site.
|
|
57
|
+
const row = await getContentById(db, null, args.id);
|
|
58
|
+
if (!row)
|
|
59
|
+
return null;
|
|
60
|
+
if (!isGraphQLEnabled(config, row.contentTypeName))
|
|
61
|
+
return null;
|
|
62
|
+
if (row.status === 'published')
|
|
63
|
+
return row;
|
|
64
|
+
return canSeeDrafts(ctx, row.siteId) ? row : null;
|
|
65
|
+
},
|
|
66
|
+
contentBySlug: async (_, args, ctx) => {
|
|
67
|
+
const status = resolveStatusFilter(ctx, args.siteId, undefined);
|
|
68
|
+
const row = await getContentBySlug(db, null, args.slug, args.siteId, status ? { status } : undefined);
|
|
69
|
+
if (!row)
|
|
70
|
+
return null;
|
|
71
|
+
if (!isGraphQLEnabled(config, row.contentTypeName))
|
|
72
|
+
return null;
|
|
73
|
+
return row;
|
|
74
|
+
},
|
|
75
|
+
contentList: async (_, args, ctx) => {
|
|
10
76
|
const ct = config.contentTypes.find(c => c.name === args.contentType);
|
|
11
|
-
if (!ct)
|
|
12
|
-
|
|
77
|
+
if (!ct || !isGraphQLEnabled(config, args.contentType)) {
|
|
78
|
+
// Default-deny (#84): a missing/false `graphql` flag is a hard error,
|
|
79
|
+
// not silent emptiness — that silent-empty behavior was the bug.
|
|
80
|
+
throw new GraphQLError(`Content type "${args.contentType}" is not available via GraphQL`);
|
|
81
|
+
}
|
|
82
|
+
const status = resolveStatusFilter(ctx, args.siteId, args.status);
|
|
13
83
|
const page = args.page ?? 1;
|
|
14
84
|
const limit = args.limit ?? 10;
|
|
15
|
-
const { rows } = await listContent(db, ct, null, args.siteId, { page, limit, offset: (page - 1) * limit }, { sortField: 'createdAt', sortDir: 'desc' }, { customFields: {}, ...(
|
|
85
|
+
const { rows } = await listContent(db, ct, null, args.siteId, { page, limit, offset: (page - 1) * limit }, { sortField: 'createdAt', sortDir: 'desc' }, { customFields: {}, ...(status ? { status } : {}) });
|
|
16
86
|
return rows;
|
|
17
87
|
},
|
|
18
|
-
search: async (_, args) => {
|
|
88
|
+
search: async (_, args, ctx) => {
|
|
89
|
+
// #84: an explicit contentType arg naming a non-opted-in type is a hard
|
|
90
|
+
// error; with no arg, results are silently filtered to opted-in types
|
|
91
|
+
// rather than leaking every type's rows.
|
|
92
|
+
if (args.contentType && !isGraphQLEnabled(config, args.contentType)) {
|
|
93
|
+
throw new GraphQLError(`Content type "${args.contentType}" is not available via GraphQL`);
|
|
94
|
+
}
|
|
95
|
+
// The search schema exposes no `status` arg, so elevated access is always
|
|
96
|
+
// implicit — anonymous callers are confined to published, members may see
|
|
97
|
+
// drafts, non-members of the site are denied.
|
|
98
|
+
const status = resolveStatusFilter(ctx, args.siteId, undefined);
|
|
99
|
+
// Mirrors search-routes.ts (#82): an elevated (draft-visible) caller is
|
|
100
|
+
// an admin searching for content to edit, so it also sees rows marked
|
|
101
|
+
// excludeFromSearch; anonymous/public search never does.
|
|
102
|
+
const includeExcluded = canSeeDrafts(ctx, args.siteId);
|
|
19
103
|
const { results } = await searchContent(db, args.query, {
|
|
20
104
|
siteId: args.siteId,
|
|
21
105
|
contentType: args.contentType,
|
|
22
106
|
limit: args.limit,
|
|
107
|
+
status,
|
|
108
|
+
includeExcluded,
|
|
23
109
|
});
|
|
24
|
-
return results;
|
|
110
|
+
return results.filter(r => isGraphQLEnabled(config, r.contentTypeName));
|
|
25
111
|
},
|
|
112
|
+
// Categories are site taxonomy with no publication status column, so there
|
|
113
|
+
// is no draft/unpublished state to leak (audited for #79).
|
|
26
114
|
categories: async (_, args) => listCategories(db, args.siteId),
|
|
27
|
-
nav: async (_, args) =>
|
|
115
|
+
nav: async (_, args, ctx) => {
|
|
116
|
+
// `getNavContentForSite` returns every row regardless of status, which
|
|
117
|
+
// leaks draft titles/slugs/paths (#79). There is no status arg to reject,
|
|
118
|
+
// so post-filter: a caller without draft access for this site sees only
|
|
119
|
+
// published nodes.
|
|
120
|
+
const rows = await getNavContentForSite(db, args.siteId);
|
|
121
|
+
if (canSeeDrafts(ctx, args.siteId))
|
|
122
|
+
return rows;
|
|
123
|
+
return rows.filter(r => r.status === 'published');
|
|
124
|
+
},
|
|
28
125
|
media: async (_, args) => {
|
|
126
|
+
// Media rows carry no publication status column, so there is no draft
|
|
127
|
+
// state to leak here (audited for #79).
|
|
29
128
|
const { kywiMedia } = await import('../../schema/base.js');
|
|
30
129
|
const { eq } = await import('drizzle-orm');
|
|
31
130
|
const [row] = await db.select().from(kywiMedia).where(eq(kywiMedia.id, args.id)).limit(1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolvers.js","sourceRoot":"","sources":["../../../src/api/graphql/resolvers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolvers.js","sourceRoot":"","sources":["../../../src/api/graphql/resolvers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { GraphQLSchema } from 'graphql';
|
|
2
2
|
import type { KywiConfig } from '../../config/types.js';
|
|
3
|
-
export declare function createGraphQLSchema(
|
|
3
|
+
export declare function createGraphQLSchema(config: KywiConfig): GraphQLSchema;
|
|
4
4
|
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/api/graphql/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAMd,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAgEvD,wBAAgB,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/api/graphql/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAMd,MAAM,SAAS,CAAA;AAChB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAgEvD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,aAAa,CA8DrE"}
|
|
@@ -56,7 +56,18 @@ const SearchResultType = new GraphQLObjectType({
|
|
|
56
56
|
contentTypeName: { type: GraphQLString },
|
|
57
57
|
},
|
|
58
58
|
});
|
|
59
|
-
export function createGraphQLSchema(
|
|
59
|
+
export function createGraphQLSchema(config) {
|
|
60
|
+
// Content types opted into GraphQL (#84 — `graphql: true`, default-deny).
|
|
61
|
+
// Resolver-level enforcement is what actually denies a non-opted type
|
|
62
|
+
// (`resolvers.ts`); this only documents the opted-in set on the schema
|
|
63
|
+
// itself so introspection tells callers what's queryable instead of them
|
|
64
|
+
// discovering the allow-list by trial and error.
|
|
65
|
+
const enabledTypeNames = config.contentTypes
|
|
66
|
+
.filter(ct => ct.graphql === true)
|
|
67
|
+
.map(ct => ct.name);
|
|
68
|
+
const contentTypeArgDescription = enabledTypeNames.length > 0
|
|
69
|
+
? `Content type name. Available via GraphQL: ${enabledTypeNames.join(', ')}.`
|
|
70
|
+
: 'Content type name. No content types are currently opted into GraphQL (graphql: true).';
|
|
60
71
|
const queryType = new GraphQLObjectType({
|
|
61
72
|
name: 'Query',
|
|
62
73
|
fields: {
|
|
@@ -74,7 +85,7 @@ export function createGraphQLSchema(_config) {
|
|
|
74
85
|
contentList: {
|
|
75
86
|
type: new GraphQLList(ContentType),
|
|
76
87
|
args: {
|
|
77
|
-
contentType: { type: new GraphQLNonNull(GraphQLString) },
|
|
88
|
+
contentType: { type: new GraphQLNonNull(GraphQLString), description: contentTypeArgDescription },
|
|
78
89
|
siteId: { type: new GraphQLNonNull(GraphQLString) },
|
|
79
90
|
limit: { type: GraphQLInt },
|
|
80
91
|
page: { type: GraphQLInt },
|
|
@@ -86,7 +97,7 @@ export function createGraphQLSchema(_config) {
|
|
|
86
97
|
args: {
|
|
87
98
|
query: { type: new GraphQLNonNull(GraphQLString) },
|
|
88
99
|
siteId: { type: new GraphQLNonNull(GraphQLString) },
|
|
89
|
-
contentType: { type: GraphQLString },
|
|
100
|
+
contentType: { type: GraphQLString, description: contentTypeArgDescription },
|
|
90
101
|
limit: { type: GraphQLInt },
|
|
91
102
|
},
|
|
92
103
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/api/graphql/schema.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/api/graphql/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/api/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"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"}
|
package/dist/api/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Router } from './router.js';
|
|
2
|
+
import { resolveAuth } from './auth.js';
|
|
2
3
|
import { registerContentRoutes } from './content-routes.js';
|
|
3
4
|
import { registerSiteRoutes } from './site-routes.js';
|
|
4
5
|
import { registerAuthRoutes } from './auth-routes.js';
|
|
@@ -486,10 +487,17 @@ export async function createKywiApiHandler(options) {
|
|
|
486
487
|
if (emailProvider) {
|
|
487
488
|
registerPasswordResetRoutes(router, { config, db, emailProvider });
|
|
488
489
|
}
|
|
489
|
-
// GraphQL read-only endpoint
|
|
490
|
+
// GraphQL read-only endpoint. Resolve auth from the Authorization header and
|
|
491
|
+
// hand the resolvers a per-request context (#79). A missing/invalid header
|
|
492
|
+
// yields an anonymous context (user: null) rather than a 401 — anonymous
|
|
493
|
+
// access to published content stays legal, matching GET /search?status=published;
|
|
494
|
+
// the resolvers default-deny draft content per caller.
|
|
490
495
|
const gqlSchema = createGraphQLSchema(config);
|
|
491
496
|
const gqlResolvers = createResolvers(db, config);
|
|
492
|
-
router.post('/graphql', async (req) =>
|
|
497
|
+
router.post('/graphql', async (req) => {
|
|
498
|
+
const auth = await resolveAuth(req.headers.get('authorization'), authSecret, db);
|
|
499
|
+
return handleGraphQLRequest(gqlSchema, gqlResolvers, req, { user: auth.user });
|
|
500
|
+
});
|
|
493
501
|
// Use the resolved site UUID (kywi_webhook_endpoints.siteId is a UUID FK) so
|
|
494
502
|
// webhook delivery matches endpoints correctly — a config slug would never match.
|
|
495
503
|
const webhookDispatchSiteId = config.sites[0]
|