pointer-feedback 0.1.3 → 0.1.4
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/cli.js +117 -17
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ var init_build_constants = __esm({
|
|
|
15
15
|
"src/build-constants.ts"() {
|
|
16
16
|
"use strict";
|
|
17
17
|
BUILD_DEFAULT_SERVER = true ? "https://api.pointer.moamen.work" : "https://api.pointer.moamen.work";
|
|
18
|
-
BUILD_CLI_VERSION = true ? "0.1.
|
|
18
|
+
BUILD_CLI_VERSION = true ? "0.1.4" : "0.0.0-dev";
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -1244,6 +1244,8 @@ async function injectStatic(cwd2, htmlPath, cfg) {
|
|
|
1244
1244
|
const pinnedProps = cfg.pin ? `
|
|
1245
1245
|
s.integrity = '${cfg.pin.integrity}';
|
|
1246
1246
|
s.crossOrigin = 'anonymous';` : "";
|
|
1247
|
+
const pinnedAttrs = cfg.pin ? ` integrity="${cfg.pin.integrity}" crossorigin="anonymous"` : "";
|
|
1248
|
+
const multiEnv = (cfg.environments?.length ?? 0) > 1 || Object.keys(cfg.envMap ?? {}).length > 0;
|
|
1247
1249
|
const block = cfg.envGuarded ? `<!-- pointer-feedback:start -->
|
|
1248
1250
|
<script>
|
|
1249
1251
|
if (
|
|
@@ -1254,19 +1256,61 @@ async function injectStatic(cwd2, htmlPath, cfg) {
|
|
|
1254
1256
|
s.src = '%VITE_POINTER_SERVER%/pointer.js${pinnedSrc}';${pinnedProps}
|
|
1255
1257
|
s.defer = true;
|
|
1256
1258
|
document.head.appendChild(s);
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1259
|
+
// Deferred until the body exists. Injected just above </body> this is already true, but the
|
|
1260
|
+
// block gets copied into other files by hand, and inside <head> document.body is null \u2014
|
|
1261
|
+
// "Cannot read properties of null (reading 'appendChild')", and nothing mounts.
|
|
1262
|
+
var mount = function () {
|
|
1263
|
+
if (document.querySelector('pointer-feedback')) return;
|
|
1264
|
+
var el = document.createElement('pointer-feedback');
|
|
1265
|
+
el.setAttribute('project', '%VITE_POINTER_PROJECT%');
|
|
1266
|
+
el.setAttribute('server', '%VITE_POINTER_SERVER%');
|
|
1267
|
+
el.setAttribute('environment', '%VITE_POINTER_ENV%');
|
|
1268
|
+
el.setAttribute('source-attr', 'data-component-source');
|
|
1269
|
+
document.body.appendChild(el);
|
|
1270
|
+
};
|
|
1271
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount);
|
|
1272
|
+
else mount();
|
|
1263
1273
|
}
|
|
1264
1274
|
</script>
|
|
1265
|
-
<!-- pointer-feedback:end -->` :
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1275
|
+
<!-- pointer-feedback:end -->` : multiEnv ? (
|
|
1276
|
+
// One file, several environments.
|
|
1277
|
+
//
|
|
1278
|
+
// The single-environment form writes environment="local" into the markup, which is right
|
|
1279
|
+
// until the same index.html is built for staging and production too — then every comment
|
|
1280
|
+
// from every deployment is tagged `local` and nothing can tell them apart. This form
|
|
1281
|
+
// resolves the environment from the page's own origin at runtime, using the URLs already
|
|
1282
|
+
// registered against the project, so one committed file is correct everywhere.
|
|
1283
|
+
`<!-- pointer-feedback:start -->
|
|
1284
|
+
<script${pinnedAttrs} src="${cfg.server}/pointer.js${pinnedSrc}" defer></script>
|
|
1285
|
+
<script>
|
|
1286
|
+
(function () {
|
|
1287
|
+
var ORIGINS = ${JSON.stringify(cfg.envMap ?? {})};
|
|
1288
|
+
var FALLBACK = '${cfg.environment}';
|
|
1289
|
+
function pointerEnv() {
|
|
1290
|
+
if (ORIGINS[location.origin]) return ORIGINS[location.origin];
|
|
1291
|
+
// A dev server's port changes more often than anyone updates a URL list, so localhost is
|
|
1292
|
+
// recognised by host rather than by exact origin.
|
|
1293
|
+
if (/^(localhost|127\\.0\\.0\\.1|\\[::1\\])$/.test(location.hostname)) return 'local';
|
|
1294
|
+
return FALLBACK;
|
|
1295
|
+
}
|
|
1296
|
+
function mount() {
|
|
1297
|
+
if (document.querySelector('pointer-feedback')) return;
|
|
1298
|
+
var el = document.createElement('pointer-feedback');
|
|
1299
|
+
el.setAttribute('project', '${cfg.key}');
|
|
1300
|
+
el.setAttribute('server', '${cfg.server}');
|
|
1301
|
+
el.setAttribute('environment', pointerEnv());
|
|
1302
|
+
el.setAttribute('source-attr', 'data-component-source');
|
|
1303
|
+
document.body.appendChild(el);
|
|
1304
|
+
}
|
|
1305
|
+
// document.body is null while the parser is still in <head>. Waiting for DOMContentLoaded
|
|
1306
|
+
// makes the snippet work wherever it is pasted, instead of only just above </body>.
|
|
1307
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', mount);
|
|
1308
|
+
else mount();
|
|
1309
|
+
})();
|
|
1310
|
+
</script>
|
|
1311
|
+
<!-- pointer-feedback:end -->`
|
|
1312
|
+
) : `<!-- pointer-feedback:start -->
|
|
1313
|
+
<script${pinnedAttrs} src="${cfg.server}/pointer.js${pinnedSrc}" defer></script>
|
|
1270
1314
|
<pointer-feedback project="${cfg.key}" server="${cfg.server}" environment="${cfg.environment}" source-attr="data-component-source"></pointer-feedback>
|
|
1271
1315
|
<!-- pointer-feedback:end -->`;
|
|
1272
1316
|
const re = /<!-- pointer-feedback:start -->[\s\S]*?<!-- pointer-feedback:end -->/;
|
|
@@ -2580,9 +2624,63 @@ and the pointer-init skill uses them to mount the widget for you afterwards.
|
|
|
2580
2624
|
}
|
|
2581
2625
|
}
|
|
2582
2626
|
}
|
|
2583
|
-
|
|
2627
|
+
const ALL_ENVS = ["local", "staging", "production"];
|
|
2628
|
+
let envs = String(options["environment"] ?? "").split(",").map((e) => e.trim()).filter(Boolean);
|
|
2629
|
+
const badEnv = envs.find((e) => !ALL_ENVS.includes(e));
|
|
2630
|
+
if (badEnv) {
|
|
2631
|
+
console.error(`Unknown environment "${badEnv}". Valid values: ${ALL_ENVS.join(", ")}.`);
|
|
2632
|
+
process.exit(2);
|
|
2633
|
+
}
|
|
2584
2634
|
if (!isYes && !options["environment"]) {
|
|
2585
|
-
|
|
2635
|
+
envs = await multiSelect("Which environments does this codebase run in?", ALL_ENVS, ["local"]);
|
|
2636
|
+
}
|
|
2637
|
+
if (envs.length === 0)
|
|
2638
|
+
envs = ["local"];
|
|
2639
|
+
const env = ALL_ENVS.filter((e) => envs.includes(e))[0] ?? "local";
|
|
2640
|
+
const projectRow = await api(server, "/api/admin/projects", { token }).then((rows) => rows.find((p) => p.key === finalProjectKey)).catch(() => null);
|
|
2641
|
+
if (projectRow?.id) {
|
|
2642
|
+
const activation = {};
|
|
2643
|
+
if (envs.includes("local") && !projectRow.isActiveLocal)
|
|
2644
|
+
activation["isActiveLocal"] = true;
|
|
2645
|
+
if (envs.includes("staging") && !projectRow.isActiveStaging)
|
|
2646
|
+
activation["isActiveStaging"] = true;
|
|
2647
|
+
if (envs.includes("production") && !projectRow.isActiveProduction)
|
|
2648
|
+
activation["isActiveProduction"] = true;
|
|
2649
|
+
if (Object.keys(activation).length) {
|
|
2650
|
+
try {
|
|
2651
|
+
await api(server, `/api/admin/projects/${projectRow.id}`, {
|
|
2652
|
+
method: "PATCH",
|
|
2653
|
+
body: activation,
|
|
2654
|
+
token
|
|
2655
|
+
});
|
|
2656
|
+
} catch (err) {
|
|
2657
|
+
if (!isJson) {
|
|
2658
|
+
console.error(
|
|
2659
|
+
`Note: could not activate ${Object.keys(activation).length} environment(s) for this project (${err?.message ?? err}). An admin can switch them on in the dashboard.`
|
|
2660
|
+
);
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
const envMap = {};
|
|
2666
|
+
if (projectRow?.id && envs.length > 1) {
|
|
2667
|
+
try {
|
|
2668
|
+
const [urls, environments] = await Promise.all([
|
|
2669
|
+
api(server, `/api/admin/projects/${projectRow.id}/app-urls`, { token }),
|
|
2670
|
+
api(server, "/api/admin/environments", { token })
|
|
2671
|
+
]);
|
|
2672
|
+
const nameById = new Map((environments ?? []).map((e) => [e.id, String(e.name ?? "").toLowerCase()]));
|
|
2673
|
+
for (const row of urls ?? []) {
|
|
2674
|
+
const name = nameById.get(row.appEnvironmentId);
|
|
2675
|
+
if (!name || !row.url || !envs.includes(name))
|
|
2676
|
+
continue;
|
|
2677
|
+
try {
|
|
2678
|
+
envMap[new URL(row.url).origin] = name;
|
|
2679
|
+
} catch {
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
} catch {
|
|
2683
|
+
}
|
|
2586
2684
|
}
|
|
2587
2685
|
let appUrl = options["app-url"];
|
|
2588
2686
|
let noAppUrl = options["no-app-url"];
|
|
@@ -2652,7 +2750,9 @@ and the pointer-init skill uses them to mount the widget for you afterwards.
|
|
|
2652
2750
|
server,
|
|
2653
2751
|
key: finalProjectKey,
|
|
2654
2752
|
environment: env,
|
|
2655
|
-
pin
|
|
2753
|
+
pin,
|
|
2754
|
+
envMap,
|
|
2755
|
+
environments: envs
|
|
2656
2756
|
});
|
|
2657
2757
|
filesMod = [htmlPath];
|
|
2658
2758
|
injected = true;
|
|
@@ -2664,7 +2764,7 @@ and the pointer-init skill uses them to mount the widget for you afterwards.
|
|
|
2664
2764
|
if (!isJson)
|
|
2665
2765
|
console.log(`Injected widget into ${filesMod.join(", ")}`);
|
|
2666
2766
|
} else if (appInfo.kind === "static") {
|
|
2667
|
-
const htmlPath = await injectStatic(cwd2, options["html"], { server, key: finalProjectKey, environment: env, pin });
|
|
2767
|
+
const htmlPath = await injectStatic(cwd2, options["html"], { server, key: finalProjectKey, environment: env, pin, envMap, environments: envs });
|
|
2668
2768
|
filesMod = [htmlPath];
|
|
2669
2769
|
injected = true;
|
|
2670
2770
|
if (!isJson)
|
|
@@ -2715,7 +2815,7 @@ and the pointer-init skill uses them to mount the widget for you afterwards.
|
|
|
2715
2815
|
const mergedStack = mergeStack(stackMeta, serverStackResponse?.data ?? serverStackResponse, noDesign ? null : designBlock);
|
|
2716
2816
|
await writeStackFile(cwd2, mergedStack);
|
|
2717
2817
|
const injectedHtml = injected ? filesMod.find((f) => f.toLowerCase().endsWith(".html"))?.replace(`${cwd2}/`, "") : void 0;
|
|
2718
|
-
await writeConfig(cwd2, { server, project: finalProjectKey, environment: env, aiTool: tool, skillsDir: options["skills-dir"], cliVersion: BUILD_CLI_VERSION, htmlPath: injectedHtml });
|
|
2818
|
+
await writeConfig(cwd2, { server, project: finalProjectKey, environment: env, aiTool: tool, skillsDir: options["skills-dir"], cliVersion: BUILD_CLI_VERSION, htmlPath: injectedHtml, environments: envs.length > 1 ? envs : void 0 });
|
|
2719
2819
|
filesMod.push(".pointer/config.json");
|
|
2720
2820
|
filesMod.push(".pointer/credentials.env");
|
|
2721
2821
|
filesMod.push(".gitignore");
|
package/package.json
CHANGED