@puzzmo/sdk 0.0.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +80 -260
  2. package/dist/createSimulator-9IxV0l3_.js +2749 -0
  3. package/dist/createSimulator-9IxV0l3_.js.map +1 -0
  4. package/dist/createSimulator-DxhvbnJB.cjs +1428 -0
  5. package/dist/createSimulator-DxhvbnJB.cjs.map +1 -0
  6. package/dist/index.cjs +2 -2
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +3 -13
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +267 -14
  11. package/dist/index.js.map +1 -1
  12. package/dist/objectSpread2-C4RR_HMd.cjs +1 -0
  13. package/dist/objectSpread2-CJo2CZQ6.js +76 -0
  14. package/dist/sdk.d.ts +61 -0
  15. package/dist/sdk.d.ts.map +1 -0
  16. package/dist/simulator/createSimulator.d.ts +41 -0
  17. package/dist/simulator/createSimulator.d.ts.map +1 -0
  18. package/dist/simulator/fixtures.d.ts +18 -0
  19. package/dist/simulator/fixtures.d.ts.map +1 -0
  20. package/dist/simulator/index.cjs +1 -0
  21. package/dist/simulator/index.d.ts +3 -0
  22. package/dist/simulator/index.d.ts.map +1 -0
  23. package/dist/simulator/index.js +2 -0
  24. package/dist/simulator/messaging.d.ts +12 -0
  25. package/dist/simulator/messaging.d.ts.map +1 -0
  26. package/dist/simulator/standalone.cjs +2 -0
  27. package/dist/simulator/standalone.cjs.map +1 -0
  28. package/dist/simulator/standalone.d.ts +7 -0
  29. package/dist/simulator/standalone.d.ts.map +1 -0
  30. package/dist/simulator/standalone.js +19 -0
  31. package/dist/simulator/standalone.js.map +1 -0
  32. package/dist/simulator/state.d.ts +12 -0
  33. package/dist/simulator/state.d.ts.map +1 -0
  34. package/dist/simulator/styles.d.ts +2 -0
  35. package/dist/simulator/styles.d.ts.map +1 -0
  36. package/dist/simulator/types.d.ts +72 -0
  37. package/dist/simulator/types.d.ts.map +1 -0
  38. package/dist/simulator/views/AuthView.d.ts +3 -0
  39. package/dist/simulator/views/AuthView.d.ts.map +1 -0
  40. package/dist/simulator/views/CheckpointsView.d.ts +3 -0
  41. package/dist/simulator/views/CheckpointsView.d.ts.map +1 -0
  42. package/dist/simulator/views/CtrlView.d.ts +3 -0
  43. package/dist/simulator/views/CtrlView.d.ts.map +1 -0
  44. package/dist/simulator/views/DataView.d.ts +3 -0
  45. package/dist/simulator/views/DataView.d.ts.map +1 -0
  46. package/dist/simulator/views/DoneView.d.ts +3 -0
  47. package/dist/simulator/views/DoneView.d.ts.map +1 -0
  48. package/dist/simulator/views/FeaturesView.d.ts +4 -0
  49. package/dist/simulator/views/FeaturesView.d.ts.map +1 -0
  50. package/dist/simulator/views/MsgsView.d.ts +6 -0
  51. package/dist/simulator/views/MsgsView.d.ts.map +1 -0
  52. package/dist/simulator/views/ThemeView.d.ts +3 -0
  53. package/dist/simulator/views/ThemeView.d.ts.map +1 -0
  54. package/dist/simulator/views/ThumbView.d.ts +6 -0
  55. package/dist/simulator/views/ThumbView.d.ts.map +1 -0
  56. package/dist/simulator/views/index.d.ts +10 -0
  57. package/dist/simulator/views/index.d.ts.map +1 -0
  58. package/dist/themes.d.ts +46 -0
  59. package/dist/themes.d.ts.map +1 -0
  60. package/dist/types.d.ts +232 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/dist/vite.cjs +11 -0
  63. package/dist/vite.cjs.map +1 -0
  64. package/dist/vite.d.ts +16 -0
  65. package/dist/vite.d.ts.map +1 -0
  66. package/dist/vite.js +45 -0
  67. package/dist/vite.js.map +1 -0
  68. package/dist/workshop.d.ts +7 -145
  69. package/dist/workshop.d.ts.map +1 -1
  70. package/package.json +22 -16
  71. package/dist/index.iife.js +0 -2
  72. package/dist/index.iife.js.map +0 -1
  73. package/dist/index.umd.js +0 -2
  74. package/dist/index.umd.js.map +0 -1
  75. package/dist/puzzmoSDK.d.ts +0 -237
package/dist/vite.js ADDED
@@ -0,0 +1,45 @@
1
+ function e(e, t) {
2
+ if (e == null) return {};
3
+ var n = {};
4
+ for (var r in e) if ({}.hasOwnProperty.call(e, r)) {
5
+ if (t.includes(r)) continue;
6
+ n[r] = e[r];
7
+ }
8
+ return n;
9
+ }
10
+ function t(t, n) {
11
+ if (t == null) return {};
12
+ var r, i, a = e(t, n);
13
+ if (Object.getOwnPropertySymbols) {
14
+ var o = Object.getOwnPropertySymbols(t);
15
+ for (i = 0; i < o.length; i++) r = o[i], n.includes(r) || {}.propertyIsEnumerable.call(t, r) && (a[r] = t[r]);
16
+ }
17
+ return a;
18
+ }
19
+ var n = ["fixturesGlob"];
20
+ /** Vite plugin that injects the Puzzmo simulator in dev mode and handles OAuth callbacks. */
21
+ function r(e = {}) {
22
+ return {
23
+ name: "puzzmo-simulator",
24
+ apply: "serve",
25
+ configureServer(e) {
26
+ e.middlewares.use("/oauth/callback", (e, t) => {
27
+ t.setHeader("Content-Type", "text/html"), t.end("<!DOCTYPE html>\n<html><head><title>Puzzmo OAuth</title></head>\n<body><script>\nvar params = new URLSearchParams(window.location.search);\nvar returnUrl = sessionStorage.getItem(\"oauth_return_url\") || \"/\";\nvar url = new URL(returnUrl);\nparams.forEach(function(v, k) { url.searchParams.set(k, v); });\nwindow.location.href = url.toString();\n<\/script></body></html>");
28
+ });
29
+ },
30
+ transformIndexHtml() {
31
+ let { fixturesGlob: r } = e, i = t(e, n), a = ["import { createSimulator } from \"@puzzmo/sdk/simulator\""];
32
+ r && a.push(`const fixtures = import.meta.glob(${JSON.stringify(r)}, { eager: true })`);
33
+ let o = Object.entries(i).filter(([, e]) => e !== void 0).map(([e, t]) => `${e}: ${JSON.stringify(t)}`);
34
+ return r && o.push("fixtures"), a.push(`createSimulator({ ${o.join(", ")} })`), [{
35
+ tag: "script",
36
+ attrs: { type: "module" },
37
+ children: a.join("\n"),
38
+ injectTo: "head"
39
+ }];
40
+ }
41
+ };
42
+ }
43
+ export { r as puzzmoSimulator };
44
+
45
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.js","names":[],"sources":["../src/vite.ts"],"sourcesContent":["import type { Plugin } from \"vite\"\n\nexport type PuzzmoSimulatorPluginOptions = {\n /** Path to the puzzle JSON file (default: \"./sample-puzzle.json\") */\n puzzlePath?: string\n /** Whether to auto-start the game after READY (default: true) */\n autoStart?: boolean\n /** Initial collapsed state (default: true) */\n collapsed?: boolean\n /** Game slug for API features (e.g. \"crossword\", \"my-game\") */\n slug?: string\n /** Glob pattern for fixture files, passed to import.meta.glob (e.g. \"./fixtures/puzzles/**\\/*.json\") */\n fixturesGlob?: string\n}\n\n/** Vite plugin that injects the Puzzmo simulator in dev mode and handles OAuth callbacks. */\nexport function puzzmoSimulator(options: PuzzmoSimulatorPluginOptions = {}): Plugin {\n return {\n name: \"puzzmo-simulator\",\n apply: \"serve\",\n\n configureServer(server) {\n server.middlewares.use(\"/oauth/callback\", (_req, res) => {\n res.setHeader(\"Content-Type\", \"text/html\")\n res.end(`<!DOCTYPE html>\n<html><head><title>Puzzmo OAuth</title></head>\n<body><script>\nvar params = new URLSearchParams(window.location.search);\nvar returnUrl = sessionStorage.getItem(\"oauth_return_url\") || \"/\";\nvar url = new URL(returnUrl);\nparams.forEach(function(v, k) { url.searchParams.set(k, v); });\nwindow.location.href = url.toString();\n</script></body></html>`)\n })\n },\n\n transformIndexHtml() {\n const { fixturesGlob, ...config } = options\n\n const lines = [\n `import { createSimulator } from \"@puzzmo/sdk/simulator\"`,\n ]\n\n if (fixturesGlob) {\n lines.push(`const fixtures = import.meta.glob(${JSON.stringify(fixturesGlob)}, { eager: true })`)\n }\n\n const configEntries = Object.entries(config).filter(([, v]) => v !== undefined)\n const configParts = configEntries.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)\n if (fixturesGlob) configParts.push(\"fixtures\")\n\n lines.push(`createSimulator({ ${configParts.join(\", \")} })`)\n\n return [\n {\n tag: \"script\",\n attrs: { type: \"module\" },\n children: lines.join(\"\\n\"),\n injectTo: \"head\",\n },\n ]\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;SAqCc,eAAA;;AArBd,SAAgB,EAAgB,IAAwC,EAAE,EAAU;AAClF,QAAO;EACL,MAAM;EACN,OAAO;EAEP,gBAAgB,GAAQ;AACtB,KAAO,YAAY,IAAI,oBAAoB,GAAM,MAAQ;AAEvD,IADA,EAAI,UAAU,gBAAgB,YAAY,EAC1C,EAAI,IAAI,uXAQS;KACjB;;EAGJ,qBAAqB;GACnB,IAAM,EAAE,oBAAA,GAAiB,IAAA,EAAW,GAAA,EAAA,EAE9B,IAAQ,CACZ,4DACD;AAED,GAAI,KACF,EAAM,KAAK,qCAAqC,KAAK,UAAU,EAAa,CAAC,oBAAoB;GAInG,IAAM,IADgB,OAAO,QAAQ,EAAO,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAA,EAAU,CAC7C,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,IAAI,KAAK,UAAU,EAAE,GAAG;AAK/E,UAJI,KAAc,EAAY,KAAK,WAAW,EAE9C,EAAM,KAAK,qBAAqB,EAAY,KAAK,KAAK,CAAC,KAAK,EAErD,CACL;IACE,KAAK;IACL,OAAO,EAAE,MAAM,UAAU;IACzB,UAAU,EAAM,KAAK,KAAK;IAC1B,UAAU;IACX,CACF;;EAEJ"}
@@ -1,178 +1,40 @@
1
- import type { GameSettingsUIComponents } from "@puzzmo-com/shared/hostAPI";
2
- /**
3
- * Severity level for validation issues.
4
- *
5
- * - `error`: Critical issue that prevents puzzle from being valid
6
- * - `warning`: Issue that should be addressed but doesn't prevent usage
7
- * - `info`: Informational message about the puzzle
8
- */
1
+ /** Severity level for validation issues */
9
2
  export type ValidationLevel = "error" | "warning" | "info";
10
- /** Represents a single validation issue found during puzzle validation. */
3
+ /** Represents a single validation issue found during puzzle validation */
11
4
  export interface ValidationIssue {
12
- /** Severity level of this validation issue */
13
5
  level: ValidationLevel;
14
- /** Human-readable description of the issue */
15
6
  message: string;
16
- /** Line number in the puzzle data where the issue occurs (1-indexed, optional) */
17
7
  line?: number;
18
- /**
19
- * Column position in the puzzle data where the issue occurs (1-indexed,
20
- * optional)
21
- */
22
8
  col?: number;
23
- /** Length of the problematic text segment for highlighting (optional) */
24
9
  length?: number;
25
10
  }
26
- /**
27
- * Complete validation report for a puzzle. Contains the overall validation
28
- * status and any issues found.
29
- */
11
+ /** Complete validation report for a puzzle */
30
12
  export interface ValidationReport {
31
- /** Whether the puzzle passed validation without errors */
32
13
  success: boolean;
33
- /** Array of validation issues found (errors, warnings, and info messages) */
34
14
  issues: ValidationIssue[];
35
15
  }
36
- /**
37
- * Types of errors that can occur during puzzle import.
38
- *
39
- * - `invalid_format`: The file format is not supported or recognized
40
- * - `parsing_error`: The file format is valid but parsing failed
41
- * - `unknown`: An unexpected error occurred during import
42
- */
43
16
  export type ImportErrorType = "invalid_format" | "parsing_error" | "unknown";
44
- /**
45
- * Custom error class for workshop import failures. Thrown by the `onImport`
46
- * function when a puzzle cannot be imported.
47
- *
48
- * @example
49
- *
50
- * ```typescript
51
- * throw new WorkshopImportError(
52
- * "invalid_format",
53
- * "Unsupported file extension: .xyz",
54
- * );
55
- * ```
56
- */
17
+ /** Custom error class for workshop import failures */
57
18
  export declare class WorkshopImportError extends Error {
58
- /** The category of import error */
59
19
  type: ImportErrorType;
60
- /** Optional underlying error that caused the import to fail */
61
20
  originalError?: unknown | undefined;
62
- constructor(
63
- /** The category of import error */
64
- type: ImportErrorType,
65
- /** Human-readable error message */
66
- message: string,
67
- /** Optional underlying error that caused the import to fail */
68
- originalError?: unknown | undefined);
21
+ constructor(type: ImportErrorType, message: string, originalError?: unknown | undefined);
69
22
  }
70
- /**
71
- * Result of a successful puzzle import operation. Contains the converted puzzle
72
- * data and optional metadata.
73
- */
23
+ /** Result of a successful puzzle import operation */
74
24
  export interface ImportResult {
75
- /**
76
- * The converted puzzle data in the target format (e.g., XD format for
77
- * crosswords)
78
- */
79
25
  data: string;
80
- /** Optional validation warnings about the imported puzzle */
81
26
  warnings?: ValidationIssue[];
82
- /** Optional puzzle title extracted from the import file */
83
27
  title?: string;
84
- /** Optional list of puzzle authors */
85
28
  authors?: string[];
86
- /** Optional list of puzzle editors */
87
29
  editors?: string[];
88
30
  }
89
- /**
90
- * Main interface for a Workshop bundle. Workshop bundles are dynamically loaded
91
- * modules that provide game-specific functionality for puzzle validation and
92
- * import.
93
- *
94
- * @example
95
- *
96
- * ```typescript
97
- * // In your workshop bundle (e.g., games/crossword/src/workshop/index.ts)
98
- * export const validator = {
99
- * validate(data: string): ValidationReport {
100
- * // Custom validation logic
101
- * return { success: true, issues: [] };
102
- * },
103
- * };
104
- *
105
- * export const importer = {
106
- * async onImport(
107
- * filename: string,
108
- * contents: string | ArrayBuffer,
109
- * ): Promise<ImportResult> {
110
- * // Custom import logic
111
- * return { data: convertedData };
112
- * },
113
- * };
114
- * ```
115
- */
31
+ /** Main interface for a Workshop bundle */
116
32
  export interface WorkshopBundle {
117
- /** Required validator for puzzle data validation */
118
33
  validator: {
119
- /**
120
- * Validates puzzle data and returns a report of issues.
121
- *
122
- * @param data - The raw puzzle data string to validate
123
- *
124
- * @returns Validation report with success status and any issues found
125
- */
126
34
  validate(data: string): Promise<ValidationReport> | ValidationReport;
127
35
  };
128
- /** Optional importer for converting external puzzle file formats */
129
36
  importer?: {
130
- /**
131
- * Imports a puzzle file and converts it to the game's native format. Should
132
- * throw `WorkshopImportError` for known failure cases.
133
- *
134
- * @param filename - Name of the file being imported
135
- * @param contents - Raw file contents (string for
136
- * text files, ArrayBuffer for binary)
137
- *
138
- * @returns Import result with converted data and optional metadata
139
- *
140
- * @throws {WorkshopImportError} For invalid or unsupported files
141
- */
142
37
  onImport(filename: string, contents: string | ArrayBuffer): Promise<ImportResult> | ImportResult;
143
38
  };
144
- /**
145
- * Optional settings configuration for embed customization in Workshop. Allows
146
- * Workshop to render a settings form for configuring embed overrides.
147
- */
148
- settings?: {
149
- /** UI component definitions for rendering the settings form */
150
- components: GameSettingsUIComponents[];
151
- /** Default values for all settings */
152
- defaults: Record<string, unknown>;
153
- };
154
- editor?: {
155
- /** Called when first visiting a puzzle page. */
156
- mount: (element: HTMLElement, config: {
157
- puzzleString: string;
158
- onChange: (puzzleString: string) => void;
159
- theme: "light" | "dark";
160
- width: number;
161
- height: number;
162
- }) => Promise<{
163
- unmount: () => void;
164
- /**
165
- * Called whenever the puzzle string is updated in the editor from the
166
- * outside, or when the theme or dimensions update. Workshop will rely on
167
- * validator to reject / accept updates.
168
- */
169
- update: (config: {
170
- puzzleString?: string;
171
- theme?: "light" | "dark";
172
- width?: number;
173
- height?: number;
174
- }) => void;
175
- }>;
176
- };
177
39
  }
178
40
  //# sourceMappingURL=workshop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workshop.d.ts","sourceRoot":"","sources":["../src/workshop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workshop.d.ts","sourceRoot":"","sources":["../src/workshop.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;AAE1D,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,eAAe,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,eAAe,GAAG,SAAS,CAAA;AAE5E,sDAAsD;AACtD,qBAAa,mBAAoB,SAAQ,KAAK;IAEnC,IAAI,EAAE,eAAe;IAErB,aAAa,CAAC,EAAE,OAAO;gBAFvB,IAAI,EAAE,eAAe,EAC5B,OAAO,EAAE,MAAM,EACR,aAAa,CAAC,EAAE,OAAO,YAAA;CAKjC;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,2CAA2C;AAC3C,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE;QACT,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAAA;KACrE,CAAA;IACD,QAAQ,CAAC,EAAE;QACT,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAA;KACjG,CAAA;CACF"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@puzzmo/sdk",
3
- "version": "0.0.6",
4
- "description": "Puzzmo runtime and API access for games",
3
+ "version": "1.0.0",
4
+ "description": "Puzzmo runtime SDK for game developers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -11,19 +11,29 @@
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js",
13
13
  "require": "./dist/index.cjs"
14
+ },
15
+ "./simulator": {
16
+ "types": "./dist/simulator/index.d.ts",
17
+ "import": "./dist/simulator/index.js",
18
+ "require": "./dist/simulator/index.cjs"
19
+ },
20
+ "./simulator/standalone": {
21
+ "types": "./dist/simulator/standalone.d.ts",
22
+ "import": "./dist/simulator/standalone.js",
23
+ "require": "./dist/simulator/standalone.cjs"
24
+ },
25
+ "./vite": {
26
+ "types": "./dist/vite.d.ts",
27
+ "import": "./dist/vite.js",
28
+ "require": "./dist/vite.cjs"
14
29
  }
15
30
  },
16
31
  "files": [
17
32
  "dist"
18
33
  ],
19
34
  "scripts": {
20
- "generate-sdk": "tsx scripts/generateSDK.ts",
21
- "generate-sdk:watch": "tsx scripts/generateSDK.ts --watch",
22
- "copy-sdk-types": "cp src/puzzmoSDK.d.ts dist/puzzmoSDK.d.ts",
23
- "build": "yarn generate-sdk && vite build && tsc --project tsconfig.build.json && yarn copy-sdk-types",
24
- "type-check": "tsc --noEmit",
25
- "test": "vitest run",
26
- "test:watch": "vitest"
35
+ "build": "vite build && tsc --project tsconfig.build.json",
36
+ "type-check": "tsc --noEmit"
27
37
  },
28
38
  "keywords": [
29
39
  "puzzmo",
@@ -34,20 +44,16 @@
34
44
  "license": "MIT",
35
45
  "repository": {
36
46
  "type": "git",
37
- "url": "git+https://github.com/puzzmo-com/games.git",
47
+ "url": "git+https://github.com/puzzmo-com/oss.git",
38
48
  "directory": "packages/sdk"
39
49
  },
40
50
  "publishConfig": {
41
51
  "access": "public",
52
+ "provenance": true,
42
53
  "registry": "https://registry.npmjs.org/"
43
54
  },
44
55
  "devDependencies": {
45
- "@puzzmo-com/shared": "^0.0.14332",
46
- "prettier": "^3.6.2",
47
- "prettier-plugin-jsdoc": "^1.5.0",
48
- "tsx": "catalog:",
49
56
  "typescript": "catalog:",
50
- "vite": "catalog:",
51
- "vitest": "catalog:"
57
+ "vite": "catalog:"
52
58
  }
53
59
  }
@@ -1,2 +0,0 @@
1
- var PuzzmoSDK=function(r){"use strict";class t extends Error{constructor(n,u,l){super(u),this.type=n,this.originalError=l,this.name="WorkshopImportError"}}function e(o){return{hello:()=>{console.log("Hello from Puzzmo SDK!",o)}}}return r.WorkshopImportError=t,r.createPuzzmoSDK=e,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}),r}({});
2
- //# sourceMappingURL=index.iife.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.iife.js","sources":["../src/workshop.ts","../src/index.ts"],"sourcesContent":["import type { GameSettingsUIComponents } from \"@puzzmo-com/shared/hostAPI\";\n\n/**\n * Severity level for validation issues.\n *\n * - `error`: Critical issue that prevents puzzle from being valid\n * - `warning`: Issue that should be addressed but doesn't prevent usage\n * - `info`: Informational message about the puzzle\n */\nexport type ValidationLevel = \"error\" | \"warning\" | \"info\";\n\n/** Represents a single validation issue found during puzzle validation. */\nexport interface ValidationIssue {\n /** Severity level of this validation issue */\n level: ValidationLevel;\n /** Human-readable description of the issue */\n message: string;\n /** Line number in the puzzle data where the issue occurs (1-indexed, optional) */\n line?: number;\n /**\n * Column position in the puzzle data where the issue occurs (1-indexed,\n * optional)\n */\n col?: number;\n /** Length of the problematic text segment for highlighting (optional) */\n length?: number;\n}\n\n/**\n * Complete validation report for a puzzle. Contains the overall validation\n * status and any issues found.\n */\nexport interface ValidationReport {\n /** Whether the puzzle passed validation without errors */\n success: boolean;\n /** Array of validation issues found (errors, warnings, and info messages) */\n issues: ValidationIssue[];\n}\n\n/**\n * Types of errors that can occur during puzzle import.\n *\n * - `invalid_format`: The file format is not supported or recognized\n * - `parsing_error`: The file format is valid but parsing failed\n * - `unknown`: An unexpected error occurred during import\n */\nexport type ImportErrorType = \"invalid_format\" | \"parsing_error\" | \"unknown\";\n\n/**\n * Custom error class for workshop import failures. Thrown by the `onImport`\n * function when a puzzle cannot be imported.\n *\n * @example\n *\n * ```typescript\n * throw new WorkshopImportError(\n * \"invalid_format\",\n * \"Unsupported file extension: .xyz\",\n * );\n * ```\n */\nexport class WorkshopImportError extends Error {\n constructor(\n /** The category of import error */\n public type: ImportErrorType,\n /** Human-readable error message */\n message: string,\n /** Optional underlying error that caused the import to fail */\n public originalError?: unknown,\n ) {\n super(message);\n this.name = \"WorkshopImportError\";\n }\n}\n\n/**\n * Result of a successful puzzle import operation. Contains the converted puzzle\n * data and optional metadata.\n */\nexport interface ImportResult {\n /**\n * The converted puzzle data in the target format (e.g., XD format for\n * crosswords)\n */\n data: string;\n /** Optional validation warnings about the imported puzzle */\n warnings?: ValidationIssue[];\n /** Optional puzzle title extracted from the import file */\n title?: string;\n /** Optional list of puzzle authors */\n authors?: string[];\n /** Optional list of puzzle editors */\n editors?: string[];\n}\n\n/**\n * Main interface for a Workshop bundle. Workshop bundles are dynamically loaded\n * modules that provide game-specific functionality for puzzle validation and\n * import.\n *\n * @example\n *\n * ```typescript\n * // In your workshop bundle (e.g., games/crossword/src/workshop/index.ts)\n * export const validator = {\n * validate(data: string): ValidationReport {\n * // Custom validation logic\n * return { success: true, issues: [] };\n * },\n * };\n *\n * export const importer = {\n * async onImport(\n * filename: string,\n * contents: string | ArrayBuffer,\n * ): Promise<ImportResult> {\n * // Custom import logic\n * return { data: convertedData };\n * },\n * };\n * ```\n */\nexport interface WorkshopBundle {\n /** Required validator for puzzle data validation */\n validator: {\n /**\n * Validates puzzle data and returns a report of issues.\n *\n * @param data - The raw puzzle data string to validate\n *\n * @returns Validation report with success status and any issues found\n */\n validate(data: string): Promise<ValidationReport> | ValidationReport;\n };\n /** Optional importer for converting external puzzle file formats */\n importer?: {\n /**\n * Imports a puzzle file and converts it to the game's native format. Should\n * throw `WorkshopImportError` for known failure cases.\n *\n * @param filename - Name of the file being imported\n * @param contents - Raw file contents (string for\n * text files, ArrayBuffer for binary)\n *\n * @returns Import result with converted data and optional metadata\n *\n * @throws {WorkshopImportError} For invalid or unsupported files\n */\n onImport(\n filename: string,\n contents: string | ArrayBuffer,\n ): Promise<ImportResult> | ImportResult;\n };\n /**\n * Optional settings configuration for embed customization in Workshop. Allows\n * Workshop to render a settings form for configuring embed overrides.\n */\n settings?: {\n /** UI component definitions for rendering the settings form */\n components: GameSettingsUIComponents[];\n /** Default values for all settings */\n defaults: Record<string, unknown>;\n };\n\n editor?: {\n /** Called when first visiting a puzzle page. */\n mount: (\n element: HTMLElement,\n config: {\n puzzleString: string;\n onChange: (puzzleString: string) => void;\n theme: \"light\" | \"dark\";\n width: number;\n height: number;\n },\n ) => Promise<{\n unmount: () => void;\n /**\n * Called whenever the puzzle string is updated in the editor from the\n * outside, or when the theme or dimensions update. Workshop will rely on\n * validator to reject / accept updates.\n */\n update: (config: {\n puzzleString?: string;\n theme?: \"light\" | \"dark\";\n width?: number;\n height?: number;\n }) => void;\n }>;\n };\n}\n","import { GameConfig } from \"./puzzmoSDK\";\n\n// Export the auto-generated public SDK types\nexport type * from \"./puzzmoSDK\";\n\n// Export workshop types\nexport * from \"./workshop\";\n\n/**\n * Creates a Puzzmo SDK instance\n *\n * @param config - Configuration options\n *\n * @returns A Puzzmo SDK instance\n */\nexport function createPuzzmoSDK(config: GameConfig) {\n return {\n hello: () => {\n console.log(\"Hello from Puzzmo SDK!\", config);\n },\n };\n}\n\nexport type PuzzmoSDK = ReturnType<typeof createPuzzmoSDK>;\n"],"names":["WorkshopImportError","type","message","originalError","createPuzzmoSDK","config"],"mappings":"uCA6DO,MAAMA,UAA4B,KAAM,CAC7C,YAESC,EAEPC,EAEOC,EACP,CACA,MAAMD,CAAO,EANN,KAAA,KAAAD,EAIA,KAAA,cAAAE,EAGP,KAAK,KAAO,qBACd,CACF,CC1DO,SAASC,EAAgBC,EAAoB,CAClD,MAAO,CACL,MAAO,IAAM,CACX,QAAQ,IAAI,yBAA0BA,CAAM,CAC9C,CAAA,CAEJ"}
package/dist/index.umd.js DELETED
@@ -1,2 +0,0 @@
1
- (function(o,e){typeof exports=="object"&&typeof module!="undefined"?e(exports):typeof define=="function"&&define.amd?define(["exports"],e):(o=typeof globalThis!="undefined"?globalThis:o||self,e(o.PuzzmoSDK={}))})(this,function(o){"use strict";class e extends Error{constructor(n,i,s){super(i),this.type=n,this.originalError=s,this.name="WorkshopImportError"}}function t(r){return{hello:()=>{console.log("Hello from Puzzmo SDK!",r)}}}o.WorkshopImportError=e,o.createPuzzmoSDK=t,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})});
2
- //# sourceMappingURL=index.umd.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/workshop.ts","../src/index.ts"],"sourcesContent":["import type { GameSettingsUIComponents } from \"@puzzmo-com/shared/hostAPI\";\n\n/**\n * Severity level for validation issues.\n *\n * - `error`: Critical issue that prevents puzzle from being valid\n * - `warning`: Issue that should be addressed but doesn't prevent usage\n * - `info`: Informational message about the puzzle\n */\nexport type ValidationLevel = \"error\" | \"warning\" | \"info\";\n\n/** Represents a single validation issue found during puzzle validation. */\nexport interface ValidationIssue {\n /** Severity level of this validation issue */\n level: ValidationLevel;\n /** Human-readable description of the issue */\n message: string;\n /** Line number in the puzzle data where the issue occurs (1-indexed, optional) */\n line?: number;\n /**\n * Column position in the puzzle data where the issue occurs (1-indexed,\n * optional)\n */\n col?: number;\n /** Length of the problematic text segment for highlighting (optional) */\n length?: number;\n}\n\n/**\n * Complete validation report for a puzzle. Contains the overall validation\n * status and any issues found.\n */\nexport interface ValidationReport {\n /** Whether the puzzle passed validation without errors */\n success: boolean;\n /** Array of validation issues found (errors, warnings, and info messages) */\n issues: ValidationIssue[];\n}\n\n/**\n * Types of errors that can occur during puzzle import.\n *\n * - `invalid_format`: The file format is not supported or recognized\n * - `parsing_error`: The file format is valid but parsing failed\n * - `unknown`: An unexpected error occurred during import\n */\nexport type ImportErrorType = \"invalid_format\" | \"parsing_error\" | \"unknown\";\n\n/**\n * Custom error class for workshop import failures. Thrown by the `onImport`\n * function when a puzzle cannot be imported.\n *\n * @example\n *\n * ```typescript\n * throw new WorkshopImportError(\n * \"invalid_format\",\n * \"Unsupported file extension: .xyz\",\n * );\n * ```\n */\nexport class WorkshopImportError extends Error {\n constructor(\n /** The category of import error */\n public type: ImportErrorType,\n /** Human-readable error message */\n message: string,\n /** Optional underlying error that caused the import to fail */\n public originalError?: unknown,\n ) {\n super(message);\n this.name = \"WorkshopImportError\";\n }\n}\n\n/**\n * Result of a successful puzzle import operation. Contains the converted puzzle\n * data and optional metadata.\n */\nexport interface ImportResult {\n /**\n * The converted puzzle data in the target format (e.g., XD format for\n * crosswords)\n */\n data: string;\n /** Optional validation warnings about the imported puzzle */\n warnings?: ValidationIssue[];\n /** Optional puzzle title extracted from the import file */\n title?: string;\n /** Optional list of puzzle authors */\n authors?: string[];\n /** Optional list of puzzle editors */\n editors?: string[];\n}\n\n/**\n * Main interface for a Workshop bundle. Workshop bundles are dynamically loaded\n * modules that provide game-specific functionality for puzzle validation and\n * import.\n *\n * @example\n *\n * ```typescript\n * // In your workshop bundle (e.g., games/crossword/src/workshop/index.ts)\n * export const validator = {\n * validate(data: string): ValidationReport {\n * // Custom validation logic\n * return { success: true, issues: [] };\n * },\n * };\n *\n * export const importer = {\n * async onImport(\n * filename: string,\n * contents: string | ArrayBuffer,\n * ): Promise<ImportResult> {\n * // Custom import logic\n * return { data: convertedData };\n * },\n * };\n * ```\n */\nexport interface WorkshopBundle {\n /** Required validator for puzzle data validation */\n validator: {\n /**\n * Validates puzzle data and returns a report of issues.\n *\n * @param data - The raw puzzle data string to validate\n *\n * @returns Validation report with success status and any issues found\n */\n validate(data: string): Promise<ValidationReport> | ValidationReport;\n };\n /** Optional importer for converting external puzzle file formats */\n importer?: {\n /**\n * Imports a puzzle file and converts it to the game's native format. Should\n * throw `WorkshopImportError` for known failure cases.\n *\n * @param filename - Name of the file being imported\n * @param contents - Raw file contents (string for\n * text files, ArrayBuffer for binary)\n *\n * @returns Import result with converted data and optional metadata\n *\n * @throws {WorkshopImportError} For invalid or unsupported files\n */\n onImport(\n filename: string,\n contents: string | ArrayBuffer,\n ): Promise<ImportResult> | ImportResult;\n };\n /**\n * Optional settings configuration for embed customization in Workshop. Allows\n * Workshop to render a settings form for configuring embed overrides.\n */\n settings?: {\n /** UI component definitions for rendering the settings form */\n components: GameSettingsUIComponents[];\n /** Default values for all settings */\n defaults: Record<string, unknown>;\n };\n\n editor?: {\n /** Called when first visiting a puzzle page. */\n mount: (\n element: HTMLElement,\n config: {\n puzzleString: string;\n onChange: (puzzleString: string) => void;\n theme: \"light\" | \"dark\";\n width: number;\n height: number;\n },\n ) => Promise<{\n unmount: () => void;\n /**\n * Called whenever the puzzle string is updated in the editor from the\n * outside, or when the theme or dimensions update. Workshop will rely on\n * validator to reject / accept updates.\n */\n update: (config: {\n puzzleString?: string;\n theme?: \"light\" | \"dark\";\n width?: number;\n height?: number;\n }) => void;\n }>;\n };\n}\n","import { GameConfig } from \"./puzzmoSDK\";\n\n// Export the auto-generated public SDK types\nexport type * from \"./puzzmoSDK\";\n\n// Export workshop types\nexport * from \"./workshop\";\n\n/**\n * Creates a Puzzmo SDK instance\n *\n * @param config - Configuration options\n *\n * @returns A Puzzmo SDK instance\n */\nexport function createPuzzmoSDK(config: GameConfig) {\n return {\n hello: () => {\n console.log(\"Hello from Puzzmo SDK!\", config);\n },\n };\n}\n\nexport type PuzzmoSDK = ReturnType<typeof createPuzzmoSDK>;\n"],"names":["WorkshopImportError","type","message","originalError","createPuzzmoSDK","config"],"mappings":"mPA6DO,MAAMA,UAA4B,KAAM,CAC7C,YAESC,EAEPC,EAEOC,EACP,CACA,MAAMD,CAAO,EANN,KAAA,KAAAD,EAIA,KAAA,cAAAE,EAGP,KAAK,KAAO,qBACd,CACF,CC1DO,SAASC,EAAgBC,EAAoB,CAClD,MAAO,CACL,MAAO,IAAM,CACX,QAAQ,IAAI,yBAA0BA,CAAM,CAC9C,CAAA,CAEJ"}
@@ -1,237 +0,0 @@
1
- /** Puzzmo SDK Type Definitions. */
2
-
3
- /**
4
- * The API contract between the Puzzmo game runtime, and the game. Contains a
5
- * space for different objects to handle responsibilities (via the
6
- * delegates/loaders)
7
- */
8
- export type GameConfig = {
9
- /**
10
- * An agreement between the game runner, and the games implementation
11
- * details about the fns in this type any breaking changes to how the run
12
- * time works will need to be handled by looking at this string version.
13
- */
14
- runtimeContract?: "1.0";
15
- /** The functions for setting up the game state */
16
- loader: GameDataLoader;
17
- /**
18
- * Get updates from the user-oriented changes to the puzzle board: either
19
- * everything or one when it's useful
20
- */
21
- stateSubscriber?: GameStateSubscriber;
22
- /** Lets the game DI in the color scheme for a game */
23
- theme: Theme;
24
- /** Lets a game handle lifecycle events which come from the host downwards */
25
- setLifecycleSubscriber: (sub: () => GameLifecycleSubscriber) => void;
26
- };
27
-
28
- /**
29
- * The way to think about is is the lifecycle subscriber is that it provides
30
- * hooks which the game will listen to
31
- */
32
- export type GameLifecycleSubscriber = {
33
- /**
34
- * When the theme changes in the Puzzmo app, also update the theme in the
35
- * embed/game.
36
- */
37
- updateTheme: (theme: Theme) => void;
38
- /** App starts the timer when it is ready */
39
- startGame: () => void;
40
- };
41
-
42
- /** A dumb 'json object' settings thing */
43
- export type GameSettingsUIComponents =
44
- | {
45
- id: string;
46
- type: "title";
47
- value: string;
48
- }
49
- | {
50
- id: string;
51
- type: "subtitle";
52
- value: string;
53
- }
54
- | {
55
- id: string;
56
- type: "paragraph";
57
- value: string;
58
- }
59
- | {
60
- id: string;
61
- type: "text";
62
- name: string;
63
- defaultValue: string;
64
- title: string;
65
- subtitle?: string | (() => any);
66
- textarea?: true;
67
- }
68
- | {
69
- id: string;
70
- type: "number";
71
- name: string;
72
- defaultValue: number;
73
- values: number[];
74
- title: string;
75
- subtitle?: string;
76
- }
77
- | {
78
- id: string;
79
- type: "boolean";
80
- name: string;
81
- defaultValue: boolean;
82
- title: string;
83
- subtitle?: string;
84
- }
85
- | {
86
- id: string;
87
- type: "enum";
88
- name: string;
89
- defaultValue: string;
90
- values: string[];
91
- displays: string[];
92
- title: string;
93
- subtitle?: string;
94
- }
95
- | {
96
- id: string;
97
- type: "setOptions";
98
- label: string;
99
- title: string;
100
- subtitle?: string;
101
- values: any;
102
- bgKey: keyof Theme;
103
- colorKey: keyof Theme;
104
- }
105
- | {
106
- id: string;
107
- type: "separator";
108
- key: string;
109
- }
110
- | {
111
- id: string;
112
- type: "split";
113
- content: GameSettingsUIComponents[];
114
- };
115
-
116
- /**
117
- * An object which if set will receive internal state updates and callbacks from
118
- * the inside the game.
119
- */
120
- export type GameStateSubscriber = {
121
- /** The callback when a game is completed */
122
- gameCompleted: (
123
- /** The internal state string of the completed game */
124
- state: string,
125
- /**
126
- * The essentials, though metrics* fields are replaced by deeds which can be
127
- * accessed via `config`
128
- */
129
- play: Partial<GamePlay>,
130
- /** These are legacy options, newer games will send an empty [] */
131
- pipelineStats: any[] | null,
132
- // For a small period of time, we sent leaderboards and deeds in this and the next arg positions, so you
133
- // should take into account that a game may send these from the past
134
- // Older game builds would not send this object
135
- config?: AugmentationConfig,
136
- ) => void;
137
- /** This function will get called whenever the user's state has changed */
138
- userInputStringChanged: (state: string, play?: Partial<GamePlay>) => void;
139
- /** The callback when a game has started booting up */
140
- gameLaunched?: (state: any, gameRuntimeContractVersion: string) => void;
141
- /** The callback when game victory animation has finished */
142
- showGameCompleteScreen: (
143
- context: MessagesSentFromEmbed["SHOW_GAME_COMPLETE_SCREEN"],
144
- ) => void;
145
- };
146
-
147
- export interface KeyboardConfig {
148
- /**
149
- * Whether the keyboard should be shown. Optional legacy property.
150
- *
151
- * @deprecated Use the showKeyboard prop on PlayGameKeyboard instead
152
- */
153
- show?: boolean;
154
- /**
155
- * Custom CSS styles to apply to individual keys, keyed by the character.
156
- * These styles are merged with the general keyStyles for each key.
157
- */
158
- individualKeyStyles?: {
159
- [key: string]: {
160
- text: CSSProperties;
161
- background: CSSProperties;
162
- };
163
- };
164
- /**
165
- * Custom CSS styles to apply to individual keys. Can be either React
166
- * CSSProperties or a string-based style object for compatibility with
167
- * different styling systems.
168
- */
169
- keyStyles?:
170
- | CSSProperties
171
- | {
172
- [prop: string]: string;
173
- };
174
- /**
175
- * Custom CSS styles to apply to the entire keyboard container. Uses
176
- * string-based properties for maximum compatibility.
177
- */
178
- kbdStyles?: {
179
- [prop: string]: string;
180
- };
181
- /**
182
- * Enables drag cursor functionality, allowing users to drag across the
183
- * keyboard to position a cursor before releasing to select a key. Useful
184
- * for precise input.
185
- */
186
- supportsDragCursor: boolean;
187
- /**
188
- * Defines the keyboard layout as rows of characters. Can be either:
189
- *
190
- * - A 4-tuple for standard QWERTY-style layouts [row1, row2, row3, row4?]
191
- * - An array of strings/nulls for custom layouts (null = empty row) Each
192
- * string represents one row, with each character being one key.
193
- */
194
- layout: [string, string, string, string | undefined] | (string | null)[];
195
- /**
196
- * Maps character keys to display symbols or special commands. Key =
197
- * character in layout, Value = what to display/send to game Example: { "≥":
198
- * ">" } displays ">" but sends "≥" to the game
199
- */
200
- symbols: Record<string, string>;
201
- /**
202
- * Set of keys that should be visually highlighted (different background
203
- * color). Commonly used to indicate special keys or current selection
204
- * state.
205
- */
206
- highlight: Set<string>;
207
- /**
208
- * Set of keys that should be disabled (non-interactive, grayed out). Used
209
- * to prevent input of invalid characters in current game state.
210
- */
211
- disabled: Set<string>;
212
- /**
213
- * Set of keys that should be extra-large (17.85% width vs normal 9.75%).
214
- * Typically used for important keys like space or enter.
215
- */
216
- xl: Set<string>;
217
- /**
218
- * Set of keys that should be large (14.7% width vs normal 9.75%). Used for
219
- * moderately important keys that need more space.
220
- */
221
- l: Set<string>;
222
- /**
223
- * Controls horizontal alignment of each keyboard row. Array index
224
- * corresponds to layout row index.
225
- *
226
- * - "start" = left-aligned
227
- * - "center" = center-aligned (default)
228
- * - "end" = right-aligned
229
- * - Undefined = use default (center)
230
- */
231
- rowPositioning?: ("end" | "start" | "center" | undefined)[];
232
- /**
233
- * Set of keys that should grow to fill available horizontal space. Useful
234
- * for spacebar-like keys that should expand to fill the row.
235
- */
236
- flexGrowSymbols?: Set<string>;
237
- }