fleet-waitlist-submit 0.1.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 +110 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +107 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# fleet-waitlist-submit
|
|
2
|
+
|
|
3
|
+
Server-side helper that commits waitlist signups as markdown to a developer's vault repo on GitHub. Part of the [Fleet](https://github.com/BiscayneDev/fleet) GTM toolkit.
|
|
4
|
+
|
|
5
|
+
## How it fits
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Visitor's browser
|
|
9
|
+
└─ <form> on your landing page
|
|
10
|
+
└─ POST to YOUR API route
|
|
11
|
+
└─ fleet-waitlist-submit (this package)
|
|
12
|
+
└─ GitHub commit → your vault repo
|
|
13
|
+
└─ Fleet (running locally) sees the file,
|
|
14
|
+
matches against your contacts, notifies you
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The submission flow is **markdown-first**: the signup IS a file in your vault, not a row in a DB that maps to a file. No third-party form service required.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install fleet-waitlist-submit
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Use
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
// app/api/waitlist/route.ts (Next.js example)
|
|
29
|
+
import { submit } from 'fleet-waitlist-submit'
|
|
30
|
+
|
|
31
|
+
export async function POST(req: Request) {
|
|
32
|
+
const body = await req.json()
|
|
33
|
+
|
|
34
|
+
const result = await submit({
|
|
35
|
+
githubToken: process.env.GITHUB_TOKEN!, // PAT with contents:write
|
|
36
|
+
vaultRepo: 'biscaynedev/halsey-vault', // owner/repo
|
|
37
|
+
product: 'inference', // your product slug
|
|
38
|
+
email: body.email,
|
|
39
|
+
name: body.name,
|
|
40
|
+
context: body.context,
|
|
41
|
+
source: 'web-form',
|
|
42
|
+
honeypot: body.website, // see "Spam protection" below
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
if (!result.ok) {
|
|
46
|
+
return Response.json({ error: result.error }, { status: 400 })
|
|
47
|
+
}
|
|
48
|
+
return Response.json({ ok: true })
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## API
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
submit({
|
|
56
|
+
githubToken: string, // GitHub PAT with contents:write on the vault repo
|
|
57
|
+
vaultRepo: string, // "owner/repo"
|
|
58
|
+
vaultBranch?: string, // defaults to repo's default branch
|
|
59
|
+
product: string, // lowercase letters, numbers, dashes
|
|
60
|
+
email: string, // RFC-ish validated
|
|
61
|
+
name?: string,
|
|
62
|
+
context?: string,
|
|
63
|
+
source?: string,
|
|
64
|
+
honeypot?: string, // if non-empty, silently discards
|
|
65
|
+
}) => Promise<SubmitResult>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Returns `{ ok: true, signupId, commitSha, path }` on success, `{ ok: true, discarded: true }` on honeypot hit, or `{ ok: false, error }` on validation/API failure.
|
|
69
|
+
|
|
70
|
+
## What it writes
|
|
71
|
+
|
|
72
|
+
A new file at `waitlists/<product>/signups/<timestamp-random>.md` in your vault repo:
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
---
|
|
76
|
+
id: 2026-05-16T14-32-19-987Z-3f4a8c2d1e
|
|
77
|
+
product: inference
|
|
78
|
+
email: chris@usepod.ai
|
|
79
|
+
name: Chris G
|
|
80
|
+
source: web-form
|
|
81
|
+
createdAt: 2026-05-16T14:32:19.987Z
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
Building agent infra
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Emails are normalized (lowercase, trimmed, `+alias` stripped) before storage to match Fleet's matcher convention.
|
|
88
|
+
|
|
89
|
+
## Spam protection
|
|
90
|
+
|
|
91
|
+
- **Honeypot:** Add a hidden form field (e.g. `<input type="text" name="website" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px">`). Bots fill it; humans don't. Pass it as `honeypot`. Filled means silent discard — bots don't learn they're caught.
|
|
92
|
+
- **Rate limit at your API route**, not in this package. Helper has no opinion on that.
|
|
93
|
+
- For high-volume forms, add Turnstile/hCaptcha in your handler and only call `submit()` after verification.
|
|
94
|
+
|
|
95
|
+
## GitHub token scope
|
|
96
|
+
|
|
97
|
+
Create a fine-grained PAT at <https://github.com/settings/tokens?type=beta> with:
|
|
98
|
+
- Repository access: only the vault repo
|
|
99
|
+
- Permissions: **Contents: read and write**
|
|
100
|
+
|
|
101
|
+
Store it as `GITHUB_TOKEN` in your server's env. **Never expose it client-side.**
|
|
102
|
+
|
|
103
|
+
## Related
|
|
104
|
+
|
|
105
|
+
- [Fleet](https://github.com/BiscayneDev/fleet) — the local-first GTM brain that watches your vault and runs match logic
|
|
106
|
+
- [fleet-waitlist-widget](../waitlist-widget) — drop-in React form that posts to your handler
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT © Halsey Huth
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input to the submit() helper.
|
|
3
|
+
*
|
|
4
|
+
* Call this from your landing page's server-side form handler. It commits
|
|
5
|
+
* a markdown file under `waitlists/<product>/signups/<id>.md` in the
|
|
6
|
+
* developer's vault repo. Fleet running locally watches the vault and
|
|
7
|
+
* runs match logic against the dev's contacts.
|
|
8
|
+
*/
|
|
9
|
+
export interface SubmitInput {
|
|
10
|
+
/** GitHub PAT with `contents:write` on the vault repo. */
|
|
11
|
+
githubToken: string;
|
|
12
|
+
/** Vault repo as `owner/repo`. e.g. `biscaynedev/halsey-vault`. */
|
|
13
|
+
vaultRepo: string;
|
|
14
|
+
/** Branch to commit to. Defaults to the repo's default branch. */
|
|
15
|
+
vaultBranch?: string;
|
|
16
|
+
/** Product slug (lowercase letters, numbers, dashes). */
|
|
17
|
+
product: string;
|
|
18
|
+
/** Submitter's email — required, validated. */
|
|
19
|
+
email: string;
|
|
20
|
+
/** Optional submitter name. */
|
|
21
|
+
name?: string;
|
|
22
|
+
/** Optional free-text context ("what are you building?"). */
|
|
23
|
+
context?: string;
|
|
24
|
+
/** Optional submission source (e.g. 'web-form', 'twitter-dm'). */
|
|
25
|
+
source?: string;
|
|
26
|
+
/** Honeypot field — if non-empty, the submission is silently dropped. */
|
|
27
|
+
honeypot?: string;
|
|
28
|
+
}
|
|
29
|
+
export type SubmitResult = {
|
|
30
|
+
ok: true;
|
|
31
|
+
signupId: string;
|
|
32
|
+
commitSha: string;
|
|
33
|
+
path: string;
|
|
34
|
+
} | {
|
|
35
|
+
ok: true;
|
|
36
|
+
discarded: true;
|
|
37
|
+
signupId: 'discarded';
|
|
38
|
+
} | {
|
|
39
|
+
ok: false;
|
|
40
|
+
error: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Commit a waitlist signup as a markdown file to a vault repo.
|
|
44
|
+
*
|
|
45
|
+
* Idempotency note: the signupId includes a random suffix, so the same
|
|
46
|
+
* email can be submitted multiple times without conflict (Fleet's
|
|
47
|
+
* matcher dedupes by email when surfacing matches, not by file). If
|
|
48
|
+
* you need strict one-per-email semantics, dedupe in your form handler
|
|
49
|
+
* before calling.
|
|
50
|
+
*/
|
|
51
|
+
export declare function submit(input: SubmitInput): Promise<SubmitResult>;
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAoBD,MAAM,MAAM,YAAY,GACpB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,EAAE,EAAE,IAAI,CAAC;IACT,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,WAAW,CAAC;CACvB,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAuCN;;;;;;;;GAQG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAiDtE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { Octokit } from '@octokit/rest';
|
|
3
|
+
import matter from 'gray-matter';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
const submitInputSchema = z.object({
|
|
6
|
+
githubToken: z.string().min(1),
|
|
7
|
+
vaultRepo: z
|
|
8
|
+
.string()
|
|
9
|
+
.regex(/^[^/\s]+\/[^/\s]+$/, 'vaultRepo must be in owner/repo form'),
|
|
10
|
+
vaultBranch: z.string().optional(),
|
|
11
|
+
product: z
|
|
12
|
+
.string()
|
|
13
|
+
.regex(/^[a-z0-9][a-z0-9-]*$/, {
|
|
14
|
+
message: 'product must be lowercase alphanumerics and dashes',
|
|
15
|
+
}),
|
|
16
|
+
email: z.email().max(254),
|
|
17
|
+
name: z.string().max(200).optional(),
|
|
18
|
+
context: z.string().max(2000).optional(),
|
|
19
|
+
source: z.string().max(50).optional(),
|
|
20
|
+
honeypot: z.string().optional(),
|
|
21
|
+
});
|
|
22
|
+
function normalizeEmail(email) {
|
|
23
|
+
const trimmed = email.trim().toLowerCase();
|
|
24
|
+
const atIdx = trimmed.lastIndexOf('@');
|
|
25
|
+
if (atIdx < 0)
|
|
26
|
+
return trimmed;
|
|
27
|
+
const local = trimmed.slice(0, atIdx);
|
|
28
|
+
const domain = trimmed.slice(atIdx);
|
|
29
|
+
const plusIdx = local.indexOf('+');
|
|
30
|
+
if (plusIdx < 0)
|
|
31
|
+
return trimmed;
|
|
32
|
+
return local.slice(0, plusIdx) + domain;
|
|
33
|
+
}
|
|
34
|
+
function makeSignupId() {
|
|
35
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
36
|
+
const rand = randomBytes(5).toString('hex');
|
|
37
|
+
return `${ts}-${rand}`;
|
|
38
|
+
}
|
|
39
|
+
function renderSignupMarkdown(opts) {
|
|
40
|
+
const frontmatter = {
|
|
41
|
+
id: opts.signupId,
|
|
42
|
+
product: opts.product,
|
|
43
|
+
email: opts.email,
|
|
44
|
+
createdAt: opts.createdAt,
|
|
45
|
+
};
|
|
46
|
+
if (opts.name)
|
|
47
|
+
frontmatter.name = opts.name;
|
|
48
|
+
if (opts.source)
|
|
49
|
+
frontmatter.source = opts.source;
|
|
50
|
+
return matter.stringify(opts.context, frontmatter);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Commit a waitlist signup as a markdown file to a vault repo.
|
|
54
|
+
*
|
|
55
|
+
* Idempotency note: the signupId includes a random suffix, so the same
|
|
56
|
+
* email can be submitted multiple times without conflict (Fleet's
|
|
57
|
+
* matcher dedupes by email when surfacing matches, not by file). If
|
|
58
|
+
* you need strict one-per-email semantics, dedupe in your form handler
|
|
59
|
+
* before calling.
|
|
60
|
+
*/
|
|
61
|
+
export async function submit(input) {
|
|
62
|
+
const parsed = submitInputSchema.safeParse(input);
|
|
63
|
+
if (!parsed.success) {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
error: parsed.error.issues
|
|
67
|
+
.map((i) => `${i.path.join('.')}: ${i.message}`)
|
|
68
|
+
.join('; '),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Honeypot — silently accept and drop
|
|
72
|
+
if (parsed.data.honeypot && parsed.data.honeypot.trim().length > 0) {
|
|
73
|
+
return { ok: true, discarded: true, signupId: 'discarded' };
|
|
74
|
+
}
|
|
75
|
+
const data = parsed.data;
|
|
76
|
+
const [owner, repo] = data.vaultRepo.split('/');
|
|
77
|
+
const octokit = new Octokit({ auth: data.githubToken });
|
|
78
|
+
const signupId = makeSignupId();
|
|
79
|
+
const createdAt = new Date().toISOString();
|
|
80
|
+
const path = `waitlists/${data.product}/signups/${signupId}.md`;
|
|
81
|
+
const content = renderSignupMarkdown({
|
|
82
|
+
signupId,
|
|
83
|
+
product: data.product,
|
|
84
|
+
email: normalizeEmail(data.email),
|
|
85
|
+
name: data.name,
|
|
86
|
+
source: data.source,
|
|
87
|
+
createdAt,
|
|
88
|
+
context: data.context ?? '',
|
|
89
|
+
});
|
|
90
|
+
try {
|
|
91
|
+
const res = await octokit.repos.createOrUpdateFileContents({
|
|
92
|
+
owner,
|
|
93
|
+
repo,
|
|
94
|
+
path,
|
|
95
|
+
message: `waitlist: ${data.product} signup`,
|
|
96
|
+
content: Buffer.from(content, 'utf8').toString('base64'),
|
|
97
|
+
branch: data.vaultBranch,
|
|
98
|
+
});
|
|
99
|
+
const commitSha = res.data.commit.sha ?? '';
|
|
100
|
+
return { ok: true, signupId, commitSha, path };
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
104
|
+
return { ok: false, error: `GitHub commit failed: ${message}` };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fleet-waitlist-submit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Server-side helper that commits waitlist signups as markdown to a developer's vault repo on GitHub. Part of the Fleet GTM toolkit.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"clean": "rm -rf dist",
|
|
23
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"fleet",
|
|
27
|
+
"waitlist",
|
|
28
|
+
"obsidian",
|
|
29
|
+
"vault",
|
|
30
|
+
"github",
|
|
31
|
+
"markdown",
|
|
32
|
+
"gtm"
|
|
33
|
+
],
|
|
34
|
+
"author": "Halsey Huth <halsey.huth@gmail.com>",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/BiscayneDev/fleet.git",
|
|
39
|
+
"directory": "packages/waitlist-submit"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/BiscayneDev/fleet/tree/main/packages/waitlist-submit#readme",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=20.9.0"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@octokit/rest": "^22.0.1",
|
|
47
|
+
"gray-matter": "^4.0.3",
|
|
48
|
+
"zod": "^4.3.6"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^20",
|
|
52
|
+
"typescript": "^5",
|
|
53
|
+
"vitest": "^3.2.4"
|
|
54
|
+
}
|
|
55
|
+
}
|