@joystyk/catalog 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +29 -2
  3. package/dist/advertise.d.ts +82 -0
  4. package/dist/advertise.js +203 -0
  5. package/dist/advertise.js.map +1 -0
  6. package/dist/categories.d.ts +12 -0
  7. package/dist/categories.js +45 -0
  8. package/dist/categories.js.map +1 -0
  9. package/dist/client.d.ts +1 -0
  10. package/dist/client.js +9 -0
  11. package/dist/client.js.map +1 -0
  12. package/dist/components/advertise.d.ts +4 -0
  13. package/dist/components/advertise.js +1304 -0
  14. package/dist/components/advertise.js.map +1 -0
  15. package/dist/components/app.d.ts +25 -0
  16. package/dist/components/app.js +106 -0
  17. package/dist/components/app.js.map +1 -0
  18. package/dist/components/leaving.d.ts +2 -0
  19. package/dist/components/leaving.js +104 -0
  20. package/dist/components/leaving.js.map +1 -0
  21. package/dist/components/views.d.ts +13 -0
  22. package/dist/components/views.js +1410 -0
  23. package/dist/components/views.js.map +1 -0
  24. package/dist/head.d.ts +6 -0
  25. package/dist/head.js +33 -0
  26. package/dist/head.js.map +1 -0
  27. package/dist/index.d.ts +11 -0
  28. package/dist/index.js +12 -0
  29. package/dist/labels.d.ts +10 -0
  30. package/dist/labels.js +27 -0
  31. package/dist/labels.js.map +1 -0
  32. package/dist/placeholders.d.ts +3 -0
  33. package/dist/placeholders.js +7 -0
  34. package/dist/placeholders.js.map +1 -0
  35. package/dist/registry.d.ts +46 -0
  36. package/dist/registry.js +106 -0
  37. package/dist/registry.js.map +1 -0
  38. package/dist/routes.d.ts +56 -0
  39. package/dist/routes.js +89 -0
  40. package/dist/routes.js.map +1 -0
  41. package/dist/seo.d.ts +31 -0
  42. package/dist/seo.js +174 -0
  43. package/dist/seo.js.map +1 -0
  44. package/dist/server.d.ts +50 -0
  45. package/dist/server.js +162 -0
  46. package/dist/server.js.map +1 -0
  47. package/dist/store.d.ts +202 -0
  48. package/dist/store.js +136 -0
  49. package/dist/store.js.map +1 -0
  50. package/dist/styles.css +1121 -0
  51. package/dist/wire.d.ts +108 -0
  52. package/dist/wire.js +74 -0
  53. package/dist/wire.js.map +1 -0
  54. package/package.json +63 -11
package/dist/store.js ADDED
@@ -0,0 +1,136 @@
1
+ import { CategoryInfoSchema, GameDetailSchema, GameSummaryListSchema } from "./wire.js";
2
+ import { defineStore } from "@gyral/core";
3
+ import { isGameId } from "@joystyk/contracts";
4
+ import { get } from "@gyral/http";
5
+ import * as z from "zod/mini";
6
+ //#region src/store.ts
7
+ var LoadSchema = z.enum([
8
+ "idle",
9
+ "loading",
10
+ "failed"
11
+ ]);
12
+ /** A contact form post the server rejected: what was sent, and the errors per field. */
13
+ var ContactFormSchema = z.object({
14
+ values: z.record(z.string(), z.union([z.string(), z.array(z.string())])),
15
+ errors: z.record(z.string(), z.array(z.string()))
16
+ });
17
+ /**
18
+ * Where an ad click leads: the creative's id, its approved link, that link's domain as the page
19
+ * names it, and the same-site path "Back to Joystyk" returns to.
20
+ */
21
+ var LeavingSchema = z.object({
22
+ id: z.string(),
23
+ href: z.string(),
24
+ domain: z.string(),
25
+ back: z.string()
26
+ });
27
+ var CatalogStateSchema = z.object({
28
+ /** Public origin for canonical URLs, e.g. https://joystyk.com: configuration from the server. */
29
+ origin: z.string(),
30
+ /** Categories with games. Small, so every page's seed carries it. */
31
+ categories: z.array(CategoryInfoSchema),
32
+ summaries: z.nullable(GameSummaryListSchema),
33
+ games: z.record(z.string(), GameDetailSchema),
34
+ /** Game ids the server said do not exist. */
35
+ missing: z.array(z.string()),
36
+ summariesLoad: LoadSchema,
37
+ gameLoads: z.record(z.string(), LoadSchema),
38
+ /** The advertise page's contact form after a rejected post (server-seeded only), else null. */
39
+ contactForm: z.nullable(ContactFormSchema),
40
+ /** The "You're leaving Joystyk" page's destination (server-seeded only), else null. */
41
+ leaving: z.nullable(LeavingSchema)
42
+ });
43
+ var emptyCatalog = (origin, categories = []) => ({
44
+ origin,
45
+ categories: [...categories],
46
+ summaries: null,
47
+ games: {},
48
+ missing: [],
49
+ summariesLoad: "idle",
50
+ gameLoads: {},
51
+ contactForm: null,
52
+ leaving: null
53
+ });
54
+ var statusOf = (error) => error._tag === "HttpStatusError" ? error.status : void 0;
55
+ var catalog = defineStore("joystyk/catalog", {
56
+ init: () => emptyCatalog(""),
57
+ schema: CatalogStateSchema,
58
+ update: {
59
+ LoadSummaries: (s) => s.summaries !== null || s.summariesLoad === "loading" ? s : [{
60
+ ...s,
61
+ summariesLoad: "loading"
62
+ }, [get("/api/games", {
63
+ schema: GameSummaryListSchema,
64
+ key: "catalog:summaries",
65
+ concurrency: "exhaust",
66
+ onSuccess: (summaries) => ({
67
+ _tag: "SummariesLoaded",
68
+ summaries
69
+ }),
70
+ onFailure: () => ({
71
+ _tag: "LoadFailed",
72
+ id: null
73
+ })
74
+ })]],
75
+ LoadGame: (s, { id }) => !isGameId(id) || id in s.games || s.missing.includes(id) || s.gameLoads[id] === "loading" ? s : [{
76
+ ...s,
77
+ gameLoads: {
78
+ ...s.gameLoads,
79
+ [id]: "loading"
80
+ }
81
+ }, [get(`/api/games/${encodeURIComponent(id)}`, {
82
+ schema: GameDetailSchema,
83
+ key: `catalog:game:${id}`,
84
+ concurrency: "exhaust",
85
+ onSuccess: (game) => ({
86
+ _tag: "GameLoaded",
87
+ game
88
+ }),
89
+ onFailure: (error) => statusOf(error) === 404 ? {
90
+ _tag: "GameMissing",
91
+ id
92
+ } : {
93
+ _tag: "LoadFailed",
94
+ id
95
+ }
96
+ })]],
97
+ SummariesLoaded: (s, { summaries }) => ({
98
+ ...s,
99
+ summaries,
100
+ summariesLoad: "idle"
101
+ }),
102
+ GameLoaded: (s, { game }) => ({
103
+ ...s,
104
+ games: {
105
+ ...s.games,
106
+ [game.id]: game
107
+ },
108
+ gameLoads: {
109
+ ...s.gameLoads,
110
+ [game.id]: "idle"
111
+ }
112
+ }),
113
+ GameMissing: (s, { id }) => ({
114
+ ...s,
115
+ missing: [...s.missing, id],
116
+ gameLoads: {
117
+ ...s.gameLoads,
118
+ [id]: "idle"
119
+ }
120
+ }),
121
+ LoadFailed: (s, { id }) => id === null ? {
122
+ ...s,
123
+ summariesLoad: "failed"
124
+ } : {
125
+ ...s,
126
+ gameLoads: {
127
+ ...s.gameLoads,
128
+ [id]: "failed"
129
+ }
130
+ }
131
+ }
132
+ });
133
+ //#endregion
134
+ export { CatalogStateSchema, catalog, emptyCatalog };
135
+
136
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","names":[],"sources":["../src/store.ts"],"sourcesContent":["// The catalog store: what the browser knows about the catalog. The server seeds it per\n// request with exactly what the requested page shows; client navigation fills the gaps from\n// /api/games. Loading lives here, so components only send LoadSummaries or LoadGame, and\n// every response is decoded at the boundary (core belief 9).\nimport { isGameId } from '@joystyk/contracts';\nimport { defineStore } from '@gyral/core';\nimport { get, type HttpError } from '@gyral/http';\nimport * as z from 'zod/mini';\nimport {\n CategoryInfoSchema,\n GameDetailSchema,\n GameSummaryListSchema,\n type CategoryInfo,\n type GameDetail,\n type GameSummary,\n} from './wire.ts';\n\nconst LoadSchema = z.enum(['idle', 'loading', 'failed']);\n\n/** A contact form post the server rejected: what was sent, and the errors per field. */\nconst ContactFormSchema = z.object({\n values: z.record(z.string(), z.union([z.string(), z.array(z.string())])),\n errors: z.record(z.string(), z.array(z.string())),\n});\nexport type Load = z.infer<typeof LoadSchema>;\n\n/**\n * Where an ad click leads: the creative's id, its approved link, that link's domain as the page\n * names it, and the same-site path \"Back to Joystyk\" returns to.\n */\nconst LeavingSchema = z.object({ id: z.string(), href: z.string(), domain: z.string(), back: z.string() });\nexport type Leaving = z.infer<typeof LeavingSchema>;\n\nexport const CatalogStateSchema = z.object({\n /** Public origin for canonical URLs, e.g. https://joystyk.com: configuration from the server. */\n origin: z.string(),\n /** Categories with games. Small, so every page's seed carries it. */\n categories: z.array(CategoryInfoSchema),\n summaries: z.nullable(GameSummaryListSchema),\n games: z.record(z.string(), GameDetailSchema),\n /** Game ids the server said do not exist. */\n missing: z.array(z.string()),\n summariesLoad: LoadSchema,\n gameLoads: z.record(z.string(), LoadSchema),\n /** The advertise page's contact form after a rejected post (server-seeded only), else null. */\n contactForm: z.nullable(ContactFormSchema),\n /** The \"You're leaving Joystyk\" page's destination (server-seeded only), else null. */\n leaving: z.nullable(LeavingSchema),\n});\n\nexport type CatalogState = z.infer<typeof CatalogStateSchema>;\n\nexport type CatalogMsg =\n | { readonly _tag: 'LoadSummaries' }\n | { readonly _tag: 'LoadGame'; readonly id: string }\n | { readonly _tag: 'SummariesLoaded'; readonly summaries: GameSummary[] }\n | { readonly _tag: 'GameLoaded'; readonly game: GameDetail }\n | { readonly _tag: 'GameMissing'; readonly id: string }\n | { readonly _tag: 'LoadFailed'; readonly id: string | null };\n\nexport const emptyCatalog = (origin: string, categories: readonly CategoryInfo[] = []): CatalogState => ({\n origin,\n categories: [...categories],\n summaries: null,\n games: {},\n missing: [],\n summariesLoad: 'idle',\n gameLoads: {},\n contactForm: null,\n leaving: null,\n});\n\nconst statusOf = (error: HttpError): number | undefined =>\n error._tag === 'HttpStatusError' ? error.status : undefined;\n\nexport const catalog = defineStore<CatalogState, CatalogMsg>('joystyk/catalog', {\n init: () => emptyCatalog(''),\n schema: CatalogStateSchema,\n update: {\n LoadSummaries: (s) =>\n s.summaries !== null || s.summariesLoad === 'loading'\n ? s\n : [\n { ...s, summariesLoad: 'loading' },\n [\n get('/api/games', {\n schema: GameSummaryListSchema,\n key: 'catalog:summaries',\n concurrency: 'exhaust',\n onSuccess: (summaries): CatalogMsg => ({ _tag: 'SummariesLoaded', summaries }),\n onFailure: (): CatalogMsg => ({ _tag: 'LoadFailed', id: null }),\n }),\n ],\n ],\n LoadGame: (s, { id }) =>\n !isGameId(id) || id in s.games || s.missing.includes(id) || s.gameLoads[id] === 'loading'\n ? s\n : [\n { ...s, gameLoads: { ...s.gameLoads, [id]: 'loading' } },\n [\n get(`/api/games/${encodeURIComponent(id)}`, {\n schema: GameDetailSchema,\n key: `catalog:game:${id}`,\n concurrency: 'exhaust',\n onSuccess: (game): CatalogMsg => ({ _tag: 'GameLoaded', game }),\n onFailure: (error): CatalogMsg =>\n statusOf(error) === 404 ? { _tag: 'GameMissing', id } : { _tag: 'LoadFailed', id },\n }),\n ],\n ],\n SummariesLoaded: (s, { summaries }) => ({ ...s, summaries, summariesLoad: 'idle' }),\n GameLoaded: (s, { game }) => ({\n ...s,\n games: { ...s.games, [game.id]: game },\n gameLoads: { ...s.gameLoads, [game.id]: 'idle' },\n }),\n GameMissing: (s, { id }) => ({ ...s, missing: [...s.missing, id], gameLoads: { ...s.gameLoads, [id]: 'idle' } }),\n LoadFailed: (s, { id }) =>\n id === null ? { ...s, summariesLoad: 'failed' } : { ...s, gameLoads: { ...s.gameLoads, [id]: 'failed' } },\n },\n});\n"],"mappings":"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"}