@onesub/cli 0.1.42 → 0.1.43
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/dist/__tests__/templates.test.d.ts +24 -0
- package/dist/__tests__/templates.test.d.ts.map +1 -0
- package/dist/__tests__/templates.test.js +107 -0
- package/dist/__tests__/templates.test.js.map +1 -0
- package/package.json +1 -1
- package/templates/.env.example +5 -1
- package/templates/package.json +1 -1
- package/templates/server.ts +3 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `onesub init` templates must scaffold a project on a current server.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this test exists
|
|
5
|
+
*
|
|
6
|
+
* `templates/package.json` pinned `@onesub/server: ^0.7.0` while the published server
|
|
7
|
+
* was on `0.27.0`. A caret range on a `0.x` version admits only patches — `^0.7.0`
|
|
8
|
+
* resolves to `0.7.x` — so every `onesub init` scaffolded a project **twenty minors
|
|
9
|
+
* behind**, missing the log formatter, the conditional webhook mount and the webhook
|
|
10
|
+
* authentication requirement. It had been that way since the express
|
|
11
|
+
* peerDependencies move.
|
|
12
|
+
*
|
|
13
|
+
* Nothing caught it, and that is the interesting part. Changesets bumps *workspace*
|
|
14
|
+
* versions; this file is copied template content, not a workspace, so no release step
|
|
15
|
+
* touches it. `docs:check` validates links and catalogues, not dependency ranges. The
|
|
16
|
+
* only mechanism was remembering — and twenty releases is a fair sample of how well
|
|
17
|
+
* that works.
|
|
18
|
+
*
|
|
19
|
+
* So the fix is not just the bump. Releasing a server minor now has to bump this pin
|
|
20
|
+
* too, and this test is what says so, at the release that introduces the drift rather
|
|
21
|
+
* than a year later.
|
|
22
|
+
*/
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=templates.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/templates.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `onesub init` templates must scaffold a project on a current server.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this test exists
|
|
5
|
+
*
|
|
6
|
+
* `templates/package.json` pinned `@onesub/server: ^0.7.0` while the published server
|
|
7
|
+
* was on `0.27.0`. A caret range on a `0.x` version admits only patches — `^0.7.0`
|
|
8
|
+
* resolves to `0.7.x` — so every `onesub init` scaffolded a project **twenty minors
|
|
9
|
+
* behind**, missing the log formatter, the conditional webhook mount and the webhook
|
|
10
|
+
* authentication requirement. It had been that way since the express
|
|
11
|
+
* peerDependencies move.
|
|
12
|
+
*
|
|
13
|
+
* Nothing caught it, and that is the interesting part. Changesets bumps *workspace*
|
|
14
|
+
* versions; this file is copied template content, not a workspace, so no release step
|
|
15
|
+
* touches it. `docs:check` validates links and catalogues, not dependency ranges. The
|
|
16
|
+
* only mechanism was remembering — and twenty releases is a fair sample of how well
|
|
17
|
+
* that works.
|
|
18
|
+
*
|
|
19
|
+
* So the fix is not just the bump. Releasing a server minor now has to bump this pin
|
|
20
|
+
* too, and this test is what says so, at the release that introduces the drift rather
|
|
21
|
+
* than a year later.
|
|
22
|
+
*/
|
|
23
|
+
import { describe, expect, it } from 'vitest';
|
|
24
|
+
import { readFileSync } from 'fs';
|
|
25
|
+
import { dirname, join } from 'path';
|
|
26
|
+
import { fileURLToPath } from 'url';
|
|
27
|
+
const CLI = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
28
|
+
const REPO = dirname(dirname(CLI));
|
|
29
|
+
function readJson(...parts) {
|
|
30
|
+
return JSON.parse(readFileSync(join(...parts), 'utf8'));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Does a caret range admit this version?
|
|
34
|
+
*
|
|
35
|
+
* Hand-rolled rather than pulling in `semver`, because the CLI has no runtime
|
|
36
|
+
* dependency on it and adding one to satisfy a test is the wrong trade. Only the
|
|
37
|
+
* shapes this repo actually writes are handled: `^x.y.z` and an exact version. A
|
|
38
|
+
* range this cannot parse throws rather than silently passing — a test that quietly
|
|
39
|
+
* approves an unrecognised pin is worse than no test.
|
|
40
|
+
*/
|
|
41
|
+
function caretAdmits(range, version) {
|
|
42
|
+
const v = version.split('.').map(Number);
|
|
43
|
+
if (v.length !== 3 || v.some(Number.isNaN))
|
|
44
|
+
throw new Error(`unparseable version: ${version}`);
|
|
45
|
+
if (/^\d+\.\d+\.\d+$/.test(range))
|
|
46
|
+
return range === version;
|
|
47
|
+
const m = /^\^(\d+)\.(\d+)\.(\d+)$/.exec(range);
|
|
48
|
+
if (!m)
|
|
49
|
+
throw new Error(`unhandled range shape, teach this test about it: ${range}`);
|
|
50
|
+
const [lo0, lo1, lo2] = [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
51
|
+
const [hi0, hi1, hi2] = v;
|
|
52
|
+
// Below the floor is out, whatever the majors do.
|
|
53
|
+
if (hi0 < lo0)
|
|
54
|
+
return false;
|
|
55
|
+
if (hi0 === lo0 && (hi1 < lo1 || (hi1 === lo1 && hi2 < lo2)))
|
|
56
|
+
return false;
|
|
57
|
+
// npm treats a 0.x caret as minor-locked: ^0.7.0 is >=0.7.0 <0.8.0. That is the
|
|
58
|
+
// whole reason the pin went stale, so it is the case worth being explicit about.
|
|
59
|
+
if (lo0 === 0)
|
|
60
|
+
return hi0 === 0 && hi1 === lo1;
|
|
61
|
+
return hi0 === lo0;
|
|
62
|
+
}
|
|
63
|
+
describe('caretAdmits', () => {
|
|
64
|
+
// The helper decides whether the assertion below means anything, so it is tested
|
|
65
|
+
// before it is trusted.
|
|
66
|
+
it('locks a 0.x caret to its minor', () => {
|
|
67
|
+
expect(caretAdmits('^0.7.0', '0.7.5')).toBe(true);
|
|
68
|
+
expect(caretAdmits('^0.7.0', '0.8.0')).toBe(false);
|
|
69
|
+
expect(caretAdmits('^0.7.0', '0.27.0')).toBe(false);
|
|
70
|
+
expect(caretAdmits('^0.27.0', '0.27.1')).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
it('allows minors on a stable major', () => {
|
|
73
|
+
expect(caretAdmits('^5.2.1', '5.9.0')).toBe(true);
|
|
74
|
+
expect(caretAdmits('^5.2.1', '6.0.0')).toBe(false);
|
|
75
|
+
expect(caretAdmits('^5.2.1', '5.2.0')).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
it('matches an exact pin exactly', () => {
|
|
78
|
+
expect(caretAdmits('0.27.0', '0.27.0')).toBe(true);
|
|
79
|
+
expect(caretAdmits('0.27.0', '0.27.1')).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
it('refuses to guess at a range shape it does not know', () => {
|
|
82
|
+
expect(() => caretAdmits('>=0.27 <1', '0.27.0')).toThrow(/unhandled range shape/);
|
|
83
|
+
expect(() => caretAdmits('~0.27.0', '0.27.0')).toThrow(/unhandled range shape/);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe('onesub init templates', () => {
|
|
87
|
+
const serverVersion = readJson(REPO, 'packages/server/package.json').version;
|
|
88
|
+
it('scaffolds a project that can install the current server', () => {
|
|
89
|
+
const range = readJson(CLI, 'templates/package.json')
|
|
90
|
+
.dependencies['@onesub/server'];
|
|
91
|
+
expect(range).toBeDefined();
|
|
92
|
+
expect(caretAdmits(range, serverVersion), `templates/package.json pins @onesub/server ${range}, which cannot install ` +
|
|
93
|
+
`${serverVersion}. On a 0.x version a caret admits only patches, so bump the ` +
|
|
94
|
+
`pin in the same change as the server release.`).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
it('keeps every template the CLI copies present', () => {
|
|
97
|
+
// A missing template makes `onesub init` produce a half-scaffolded project, and
|
|
98
|
+
// the failure surfaces at the user rather than here.
|
|
99
|
+
const src = readFileSync(join(CLI, 'src/index.ts'), 'utf8');
|
|
100
|
+
const declared = [...src.matchAll(/\{\s*src:\s*'([^']+)'/g)].map((m) => m[1]);
|
|
101
|
+
expect(declared.length).toBeGreaterThan(3);
|
|
102
|
+
for (const file of declared) {
|
|
103
|
+
expect(() => readFileSync(join(CLI, 'templates', file), 'utf8')).not.toThrow();
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
//# sourceMappingURL=templates.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.test.js","sourceRoot":"","sources":["../../src/__tests__/templates.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/templates/.env.example
CHANGED
|
@@ -7,8 +7,12 @@ APPLE_SHARED_SECRET=your_shared_secret
|
|
|
7
7
|
# Service account JSON from Google Cloud Console (single-line)
|
|
8
8
|
GOOGLE_PACKAGE_NAME=com.yourapp.id
|
|
9
9
|
GOOGLE_SERVICE_ACCOUNT_KEY={"type":"service_account","project_id":"..."}
|
|
10
|
-
#
|
|
10
|
+
# REQUIRED IN PRODUCTION: the Pub/Sub push endpoint URL, verified as the OIDC `aud`.
|
|
11
|
+
# Without it the Google webhook cannot attribute a request to Google and answers 401
|
|
12
|
+
# when NODE_ENV=production. Leave it unset for local development.
|
|
11
13
|
# GOOGLE_PUSH_AUDIENCE=https://api.yourapp.com/onesub/webhook/google
|
|
14
|
+
# Restricts push tokens to your Pub/Sub service account; set it with the audience.
|
|
15
|
+
# GOOGLE_PUSH_SERVICE_ACCOUNT_EMAIL=push@your-project.iam.gserviceaccount.com
|
|
12
16
|
|
|
13
17
|
# ── Database ────────────────────────────────────────────
|
|
14
18
|
# Uncomment for Postgres; leave unset for in-memory (dev only)
|
package/templates/package.json
CHANGED
package/templates/server.ts
CHANGED
|
@@ -28,7 +28,10 @@ app.use(
|
|
|
28
28
|
? {
|
|
29
29
|
packageName: process.env.GOOGLE_PACKAGE_NAME,
|
|
30
30
|
serviceAccountKey: process.env.GOOGLE_SERVICE_ACCOUNT_KEY,
|
|
31
|
+
// Required in production: without it the RTDN webhook cannot attribute a
|
|
32
|
+
// request to Google and refuses it. See docs/SECURITY.md.
|
|
31
33
|
pushAudience: process.env.GOOGLE_PUSH_AUDIENCE,
|
|
34
|
+
pushServiceAccountEmail: process.env.GOOGLE_PUSH_SERVICE_ACCOUNT_EMAIL,
|
|
32
35
|
}
|
|
33
36
|
: undefined,
|
|
34
37
|
database: { url: dbUrl ?? '' },
|