create-glanceway-source 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -53,7 +53,7 @@ Example prompts:
53
53
  cd my-source
54
54
  npm install
55
55
 
56
- # Build: compiles TypeScript, creates dist/latest.zip
56
+ # Build: compiles source, creates dist/latest.gwsrc
57
57
  npm run build
58
58
 
59
59
  # Test: executes source with mock API, validates emitted items
@@ -63,15 +63,15 @@ npm run test
63
63
  npm run test -- --config API_TOKEN=xxx --config USERNAME=yyy
64
64
  ```
65
65
 
66
- The `dist/latest.zip` file is the importable source package.
66
+ The `dist/latest.gwsrc` file is the importable source package.
67
67
 
68
68
  ## Importing into Glanceway
69
69
 
70
70
  1. Open **Glanceway**
71
71
  2. Go to **Sources**
72
72
  3. Click **Import from file**
73
- 4. Select `dist/latest.zip`
73
+ 4. Select `dist/latest.gwsrc`
74
74
 
75
75
  ## Submitting to glanceway-sources
76
76
 
77
- To share your source with the community, [open an issue](https://github.com/codytseng/glanceway-sources/issues) on glanceway-sources with a link to your project repository.
77
+ To share your source with the community, [open an issue](https://github.com/glanceway/glanceway-sources/issues) on glanceway-sources with a link to your project repository.
package/dist/index.js CHANGED
@@ -100,7 +100,7 @@ tags: []
100
100
  # config:
101
101
  # - key: API_TOKEN
102
102
  # name: API Token
103
- # type: secret # string, number, boolean, secret, select, or list
103
+ # type: secret # string, number, boolean, secret, select, list, or multiselect
104
104
  # required: true
105
105
  # description: Your API token
106
106
  # - key: SORT
@@ -111,7 +111,17 @@ tags: []
111
111
  # options:
112
112
  # - hot
113
113
  # - new
114
- # - top
114
+ # - label: Top (All Time) # options support label/value format
115
+ # value: top
116
+ # - key: CATEGORIES
117
+ # name: Categories
118
+ # type: multiselect # like select but allows multiple choices
119
+ # options:
120
+ # - label: Technology
121
+ # value: tech
122
+ # - label: Science
123
+ # value: science
124
+ # - sports
115
125
  `;
116
126
  return manifest;
117
127
  }
@@ -168,13 +178,13 @@ function generateClaudeMd(options) {
168
178
 
169
179
  ## Project Overview
170
180
 
171
- Glanceway source: "${options.name}" by ${options.author}. This is a standalone TypeScript source for [Glanceway](https://glanceway.app), a macOS menu bar app that displays information items.
181
+ Glanceway source: "${options.name}" by ${options.author}. This is a standalone JavaScript source for [Glanceway](https://glanceway.app), a macOS menu bar app that displays information items.
172
182
 
173
183
  ## Commands
174
184
 
175
185
  \`\`\`bash
176
186
  npm install # Install dependencies
177
- npm run build # Build source into dist/ (compile + zip)
187
+ npm run build # Build source into dist/ (compile + package)
178
188
  npm run test # Test source (mock API execution + validation)
179
189
  \`\`\`
180
190
 
@@ -190,7 +200,7 @@ There is no test framework. Build the source to verify it compiles. There is no
190
200
  - \`src/index.ts\` — Source implementation (main logic)
191
201
  - \`src/types.ts\` — GlancewayAPI type definitions (do not modify)
192
202
  - \`manifest.yaml\` — Source metadata and config schema
193
- - \`scripts/build.ts\` — Build script (esbuild compile + zip)
203
+ - \`scripts/build.ts\` — Build script (esbuild compile + package)
194
204
  - \`scripts/test.ts\` — Test script (mock API + validation)
195
205
 
196
206
  ## Source Development Constraints
@@ -275,7 +285,7 @@ if (response.ok && response.json) {
275
285
 
276
286
  ### api.config.get(key: string): unknown
277
287
 
278
- Get a user-configured value by key (defined in \`manifest.yaml\` config section). Returns \`string\` for most types, \`string[]\` for \`list\` type.
288
+ Get a user-configured value by key (defined in \`manifest.yaml\` config section). Returns \`string\` for most types, \`string[]\` for \`list\` and \`multiselect\` types.
279
289
 
280
290
  ### api.config.getAll(): Record<string, unknown>
281
291
 
@@ -330,7 +340,7 @@ min_app_version: 1.2.0 # Optional: minimum Glanceway app version required
330
340
  config: # Optional: user-configurable values
331
341
  - key: API_TOKEN
332
342
  name: API Token
333
- type: secret # string, number, boolean, secret, select, or list
343
+ type: secret # string, number, boolean, secret, select, list, or multiselect
334
344
  required: true
335
345
  description: Description shown to user
336
346
  - key: TAGS
@@ -346,12 +356,43 @@ config: # Optional: user-configurable values
346
356
  options:
347
357
  - hot
348
358
  - new
349
- - top
359
+ - label: Top (All Time) # options support label/value format
360
+ value: top
361
+ - key: CATEGORIES
362
+ name: Categories
363
+ type: multiselect # like select but allows multiple choices (value type: string[])
364
+ options:
365
+ - label: Technology
366
+ value: tech
367
+ - label: Science
368
+ value: science
369
+ - sports
370
+ \`\`\`
371
+
372
+ \`select\` and \`multiselect\` options can be plain strings or label/value objects:
373
+
374
+ \`\`\`yaml
375
+ options:
376
+ - plain_value # value = "plain_value", displayed as "plain_value"
377
+ - label: Display Name # value = "actual_value", displayed as "Display Name"
378
+ value: actual_value
350
379
  \`\`\`
351
380
 
381
+ ### Config Field Types
382
+
383
+ | Type | Description | Value type |
384
+ |---------------|------------------------------------------------------|-------------|
385
+ | \`string\` | Free-form text input | \`string\` |
386
+ | \`number\` | Numeric input | \`number\` |
387
+ | \`boolean\` | Toggle switch | \`boolean\` |
388
+ | \`secret\` | Stored in macOS Keychain | \`string\` |
389
+ | \`select\` | Dropdown (requires \`options\` list) | \`string\` |
390
+ | \`list\` | Multiple string values | \`string[]\` |
391
+ | \`multiselect\` | Multiple choice from options (like select but multi) | \`string[]\` |
392
+
352
393
  ## Source Lifecycle
353
394
 
354
- TypeScript sources have two distinct phases:
395
+ JavaScript sources have two distinct phases:
355
396
 
356
397
  1. **Start phase**: When the source is first loaded, the default export function (outer closure) runs. The app does **NOT** call \`refresh()\` at this point. Sources should perform their initial data fetch here by \`await\`ing their fetch function before returning.
357
398
  2. **Refresh phase**: On each scheduled refresh interval, the app calls \`refresh()\`. This is the only time \`refresh()\` is invoked.
@@ -386,7 +427,7 @@ export default async (api: GlancewayAPI<Config>): Promise<SourceMethods> => {
386
427
  - Always make full use of the \`subtitle\` field. If the API response contains summary, description, brief, or any descriptive text, map it to \`subtitle\` so users get maximum information at a glance.
387
428
  - **Maximize items per fetch.** The app does not paginate, so each fetch should retrieve as many items as the API allows without hurting performance. The hard upper limit is **500 items** — never exceed this.
388
429
 
389
- ## TypeScript Source Code Conventions
430
+ ## Source Code Conventions
390
431
 
391
432
  ### File Structure Order
392
433
 
@@ -398,6 +439,8 @@ import type { GlancewayAPI, SourceMethods } from "./types";
398
439
  type Config = {
399
440
  API_TOKEN: string;
400
441
  TAGS: string[];
442
+ SORT: string; // select → string
443
+ CATEGORIES: string[]; // multiselect → string[]
401
444
  };
402
445
 
403
446
  // 3. Helper functions (pure utilities, no api dependency)
@@ -454,11 +497,11 @@ After building (\`npm run build\`), import into Glanceway:
454
497
  1. Open Glanceway
455
498
  2. Go to Sources
456
499
  3. Click "Import from file"
457
- 4. Select \`dist/latest.zip\`
500
+ 4. Select \`dist/latest.gwsrc\`
458
501
 
459
502
  ## Submitting to glanceway-sources
460
503
 
461
- To share your source with the community, [open an issue](https://github.com/codytseng/glanceway-sources/issues) on glanceway-sources with a link to your project repository.
504
+ To share your source with the community, [open an issue](https://github.com/glanceway/glanceway-sources/issues) on glanceway-sources with a link to your project repository.
462
505
  `;
463
506
  }
464
507
  // ─── File Operations ───────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "create-glanceway-source",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Scaffold a standalone Glanceway source project",
5
5
  "type": "module",
6
+ "homepage": "https://github.com/glanceway/create-glanceway-source",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/glanceway/create-glanceway-source.git"
10
+ },
6
11
  "bin": {
7
12
  "create-glanceway-source": "dist/index.js"
8
13
  },
@@ -81,18 +81,18 @@ async function main() {
81
81
  fs.copyFileSync(manifestPath, distManifestPath);
82
82
  console.log(" Created dist/manifest.yaml");
83
83
 
84
- // Create versioned zip
85
- const versionedZipPath = path.join(DIST_DIR, `${version}.zip`);
86
- await createZip(versionedZipPath, [
84
+ // Create versioned .gwsrc package
85
+ const versionedPath = path.join(DIST_DIR, `${version}.gwsrc`);
86
+ await createZip(versionedPath, [
87
87
  { name: "manifest.yaml", content: manifestContent },
88
88
  { name: "index.js", content: compiledJs },
89
89
  ]);
90
- console.log(` Created dist/${version}.zip`);
90
+ console.log(` Created dist/${version}.gwsrc`);
91
91
 
92
- // Create latest.zip
93
- const latestZipPath = path.join(DIST_DIR, "latest.zip");
94
- fs.copyFileSync(versionedZipPath, latestZipPath);
95
- console.log(" Created dist/latest.zip");
92
+ // Create latest.gwsrc
93
+ const latestPath = path.join(DIST_DIR, "latest.gwsrc");
94
+ fs.copyFileSync(versionedPath, latestPath);
95
+ console.log(" Created dist/latest.gwsrc");
96
96
 
97
97
  console.log("\nBuild complete!");
98
98
  }
@@ -72,7 +72,7 @@ function resolveConfig(
72
72
  const override = overrides[entry.key];
73
73
 
74
74
  if (override !== undefined) {
75
- if (entry.type === "list") {
75
+ if (entry.type === "list" || entry.type === "multiselect") {
76
76
  resolved[entry.key] = override.split(",").map((s) => s.trim());
77
77
  } else if (entry.type === "boolean") {
78
78
  resolved[entry.key] = override === "true" || override === "1";