@tokenoftrust/cli 1.2.2 → 1.2.3

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 (29) hide show
  1. package/bin/tot.mjs +1 -5
  2. package/package.json +1 -2
  3. package/src/commands/checkout.mjs +1 -1
  4. package/src/commands/dev.mjs +50 -11
  5. package/src/commands/start.mjs +22 -15
  6. package/src/commands/submit.mjs +4 -5
  7. package/src/sample.mjs +6 -1
  8. package/template/sample-store/content/chrome.html +0 -152
  9. package/template/sample-store/content/chrome.json +0 -94
  10. package/template/sample-store/content/home.html +0 -194
  11. package/template/sample-store/content/home.json +0 -50
  12. package/template/sample-store/content/pages/about.json +0 -10
  13. package/template/sample-store/content/pages/privacy.json +0 -6
  14. package/template/sample-store/content/pages/shipping-returns.json +0 -6
  15. package/template/sample-store/content/pages-html/blogs/news.html +0 -68
  16. package/template/sample-store/content/pages-html/pages/about-us.html +0 -95
  17. package/template/sample-store/content/pages-html/pages/contact-us.html +0 -68
  18. package/template/sample-store/content/pages-html/pages/privacy-policy.html +0 -65
  19. package/template/sample-store/content/pages-html/pages/shipping-returns.html +0 -77
  20. package/template/sample-store/content/themes/giant-navy.json +0 -73
  21. package/template/sample-store/public/img/hero-suicide-bunny.jpg +0 -0
  22. package/template/sample-store/public/img/hero.webp +0 -0
  23. package/template/sample-store/public/img/og.jpg +0 -0
  24. package/template/sample-store/public/logo-wordmark.png +0 -0
  25. package/template/sample-store/public/pages/home.css +0 -120
  26. package/template/sample-store/public/pages/mkt.css +0 -185
  27. package/template/sample-store/public/pages/page.css +0 -155
  28. package/template/sample-store/public/themes/giant-navy.css +0 -76
  29. package/template/sample-store/theme.json +0 -39
package/bin/tot.mjs CHANGED
@@ -5,14 +5,12 @@
5
5
  * One command a developer learns to go from an invite to a running store:
6
6
  *
7
7
  * tot start invite → running store in one command ← built (orchestrates the below, value-first)
8
- * tot start --sample FREE local preview — no login, no MCP ← built (zero-login quickstart; MCP is the upsell)
9
8
  * tot login sign in to Token of Trust (OAuth) ← built (MCP OAuth PKCE loopback; caches ~/.tot/credentials.json)
10
9
  * tot logout sign out (clear the cached session) ← built (deletes ~/.tot/credentials.json; local-only, no server revoke)
11
10
  * tot whoami who you're signed in as ← built
12
11
  * tot checkout [<tenant>] clone a store you can build on ← built
13
12
  * tot validate lint your store before you submit ← built
14
13
  * tot dev run your store locally with save→reload ← built (monorepo: host astro; standalone: runs the published runner image)
15
- * tot dev --sample run a FREE bundled sample store locally ← built (zero-login, no MCP; compliance rendering still shows)
16
14
  * tot submit submit your store for preview ← built (validate + push preview ref; MCP preview_status read-back)
17
15
  * tot doctor check this machine is ready
18
16
  * tot ideas copy-paste AI prompts that reliably wow
@@ -24,7 +22,7 @@
24
22
  * from anywhere else. Every command receives the detected context.
25
23
  *
26
24
  * This package is `@tokenoftrust/cli` (bin `tot`). Its heaviest command, `tot dev`,
27
- * bundles the moat-free storefront runner; `tot checkout/validate/submit` are
25
+ * fetches the published storefront runner; `tot checkout/validate/submit` are
28
26
  * pure Node. Dependency-free by design so `npm i -g @tokenoftrust/cli` stays light.
29
27
  */
30
28
  import { readFileSync } from "node:fs";
@@ -49,14 +47,12 @@ function usage() {
49
47
  tot — Token of Trust developer CLI
50
48
 
51
49
  tot start invite → running store in one command (start here)
52
- tot start --sample free local preview — no login, no account needed
53
50
  tot login sign in to Token of Trust
54
51
  tot logout sign out (clear the cached session)
55
52
  tot whoami show who you're signed in as
56
53
  tot checkout [<tenant>] clone a store you can build on
57
54
  tot validate lint your store before you submit
58
55
  tot dev run your store locally with save→reload
59
- tot dev --sample run a free bundled sample store (no login, no MCP)
60
56
  tot submit submit your store for preview
61
57
  tot doctor check this machine is ready
62
58
  tot ideas copy-paste AI prompts that reliably wow
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/cli",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Token of Trust developer CLI — check out a tenant store, run it locally with save→reload, and submit it for preview. Installs the `tot` command.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Token of Trust",
@@ -25,7 +25,6 @@
25
25
  "files": [
26
26
  "bin",
27
27
  "src",
28
- "template",
29
28
  "README.md",
30
29
  "LICENSE"
31
30
  ],
@@ -13,7 +13,7 @@
13
13
  * `tot` performs NO privileged forge work itself — the MCP owns that.
14
14
  *
15
15
  * Auth is resolved through src/auth.mjs: operator creds (our dogfooding / CI) or
16
- * the developer's own ToT identity (workstream #2). This command doesn't care
16
+ * the developer's own ToT identity. This command doesn't care
17
17
  * which — it just needs a validated session.
18
18
  *
19
19
  * Dependency-free (global fetch + `git` via child_process).
@@ -8,7 +8,7 @@
8
8
  * monorepo or --workspace graft mode). Fast host loop for platform devs.
9
9
  *
10
10
  * checkout — a standalone tenant checkout has no runner. `tot dev` DOWNLOADS the
11
- * published, moat-free RUNNER ARTIFACT (a plain tarball — the exact
11
+ * published, RUNNER ARTIFACT (a plain tarball — the exact
12
12
  * same tree Docker used to bake into the image, see
13
13
  * scripts/build/build-runner.mjs) and runs it NATIVELY: no Docker, no
14
14
  * container. Cached once per version under ~/.tot/cache/renderer/, so
@@ -48,7 +48,7 @@ import {
48
48
  resolveRendererSource as resolveLocalRendererSource, SAMPLE_DIR_NAME,
49
49
  } from "../sample.mjs";
50
50
 
51
- /** The published moat-free runner image (--docker fallback). Override with --image / TOT_DEV_IMAGE. */
51
+ /** The published runner image (--docker fallback). Override with --image / TOT_DEV_IMAGE. */
52
52
  const DEFAULT_DEV_IMAGE =
53
53
  "242086487598.dkr.ecr.us-east-1.amazonaws.com/tot-dev:latest";
54
54
  const DEFAULT_MCP_URL = "https://mcp.tokenoftrust.com";
@@ -147,16 +147,56 @@ async function runStandalone(workspace, args, ctx) {
147
147
  return await runNative(workspace, args, ctx);
148
148
  } catch (e) {
149
149
  if (e instanceof NativeArtifactUnavailableError) {
150
- console.error(
151
- `~ native runtime unavailable (${e.message}) falling back to the Docker runner.`,
152
- );
153
- return runContainer(workspace, args, ctx);
150
+ // Entitled artifact unavailable — stay NATIVE on the public npm runner
151
+ // (@tokenoftrust/storefront-runner, the SAME renderer bits), so
152
+ // `tot dev` never needs Docker just because dev_renderer_artifact isn't
153
+ // configured. Docker is the last resort only if the public runner is also
154
+ // unreachable (offline).
155
+ try {
156
+ console.error(`~ entitled renderer unavailable (${e.message}) — using the public runner (no Docker).`);
157
+ return await runNativePublic(workspace, args, ctx);
158
+ } catch (e2) {
159
+ if (e2 instanceof NativeArtifactUnavailableError) {
160
+ console.error(`~ public runner unavailable (${e2.message}) — falling back to the Docker runner.`);
161
+ return runContainer(workspace, args, ctx);
162
+ }
163
+ console.error(formatError(e2));
164
+ return e2 instanceof CliError ? (e2.exitCode ?? 2) : 2;
165
+ }
154
166
  }
155
167
  console.error(formatError(e));
156
168
  return e instanceof CliError ? (e.exitCode ?? 2) : 2;
157
169
  }
158
170
  }
159
171
 
172
+ /**
173
+ * Native boot against the PUBLIC/local renderer (no MCP, no
174
+ * entitlement) — the fallback for a standalone checkout when the entitled
175
+ * artifact isn't available. Mirrors runNative but resolves the renderer via
176
+ * ensureSampleRenderer (env override → cached runner → in-tree monorepo →
177
+ * public npm), which throws NativeArtifactUnavailableError when even the public
178
+ * runner can't be fetched (offline) so the caller can drop to Docker.
179
+ */
180
+ async function runNativePublic(workspace, args, ctx) {
181
+ const cfg = readWorkspaceConfig(workspace);
182
+ if (!cfg) {
183
+ throw new CliError(`${workspace} isn't a tenant checkout (no readable .tot/config.json)`, {
184
+ next: "tot checkout <tenant> --clone <dir> (produces a runnable checkout)",
185
+ exitCode: 2,
186
+ });
187
+ }
188
+ const port = String(args.port || "4321");
189
+ const { url } = deriveUrl(cfg, port);
190
+ let runnerDir;
191
+ try {
192
+ runnerDir = await ensureSampleRenderer(args, ctx);
193
+ } catch (e) {
194
+ throw new NativeArtifactUnavailableError(String(e?.message || e));
195
+ }
196
+ printDevBanner({ tenant: cfg.tenant || null, url });
197
+ return bootNative(runnerDir, workspace, port, url, args);
198
+ }
199
+
160
200
  function runMonorepo(ctx, argv) {
161
201
  const script = join(ctx.repoRoot, "scripts", "tot-dev.mjs");
162
202
  if (!existsSync(script)) {
@@ -274,7 +314,7 @@ export function printSampleBanner({ url }) {
274
314
  }
275
315
 
276
316
  /**
277
- * Resolve WHERE to get the moat-free runner tarball for this run — the seam that
317
+ * Resolve WHERE to get the runner tarball for this run — the seam that
278
318
  * splits the entitled and the public (zero-login sample) delivery paths. Returns
279
319
  * `{ kind, version, url, strip, cacheKey }`; callers download + extract + install +
280
320
  * cache it uniformly (installRunnerTarball).
@@ -297,7 +337,7 @@ export async function resolveRendererSource(args, { client } = {}) {
297
337
  }
298
338
 
299
339
  /**
300
- * PUBLIC, un-entitled source for sample / zero-login mode: the moat-free runner
340
+ * PUBLIC, un-entitled source for sample / zero-login mode: the runner
301
341
  * straight from the public npm registry — NO MCP call, NO entitlement. Reads the
302
342
  * package's registry metadata (unauthenticated JSON) for the tarball URL + version.
303
343
  * Pin with `--renderer-version` / TOT_RUNNER_VERSION, else the `latest` dist-tag.
@@ -340,7 +380,7 @@ export async function resolveEntitledRendererSource(args, { client: providedClie
340
380
  }
341
381
 
342
382
  /**
343
- * Get the moat-free renderer artifact for this host — a signed URL from the MCP
383
+ * Get the renderer artifact for this host — a signed URL from the MCP
344
384
  * (dev_renderer_artifact, same entitlement gate as the Docker pull token),
345
385
  * downloaded + extracted + `pnpm install`'d ONCE per version under
346
386
  * ~/.tot/cache/renderer/<version>/. Later runs of the same version reuse the
@@ -752,8 +792,7 @@ export function isPrivateRegistryImage(image) {
752
792
  * Entitlement-gated registry login: ask the MCP for a short-lived pull credential
753
793
  * (`dev_image_pull_token`) and `docker login` with it. Best-effort — if the MCP,
754
794
  * the session, or the tool isn't available yet, warn softly and continue (an
755
- * existing `docker login`, or the docker pull error, takes over). This is the CLI
756
- * half of ~/.tot-mcp/handoffs/2026-07-09-tot-mcp-dev-image-pull-token.md.
795
+ * existing `docker login`, or the docker pull error, takes over).
757
796
  *
758
797
  * Exported + accepts an already-authenticated `client` (C1: `tot start` reuses
759
798
  * its own session and overlaps this with the checkout clone instead of paying
@@ -93,12 +93,9 @@ const USAGE = `tot start — go from invite to a running store in one command
93
93
 
94
94
  tot start preflight → sign in → pick your store → check out →
95
95
  run it → open your browser → connect Claude
96
- tot start --sample the FREE local preview — no login, no MCP, no account:
97
- scaffold + run a sample store, then offer the MCP upsell
98
96
  Options:
99
97
  --tenant <id> use this store (skips auto-pick/prompt; remembered for next time)
100
98
  --port <n> host port for the dev server (default 4321)
101
- --sample zero-login free taste (see above); also what a no-session run offers
102
99
  --docker use the Docker runner instead of the native runtime (F3
103
100
  default); also the automatic fallback if the native
104
101
  artifact can't be fetched
@@ -183,8 +180,8 @@ export async function run(argv, ctx) {
183
180
  const session = await tryResolveSession(client, env, args);
184
181
  if (decideStartMode({ sampleFlag: false, hasSession: !!session }) === "sample") {
185
182
  if (!(await confirmSampleFallback(args))) {
186
- throw new CliError("no Token of Trust session, and you declined the free local preview", {
187
- next: "tot login (then re-run `tot start`), or `tot start --sample` for the free local preview",
183
+ throw new CliError("no Token of Trust session", {
184
+ next: "tot login (then re-run `tot start`)",
188
185
  });
189
186
  }
190
187
  return await runSampleStart(args, ctx, env, startedAt);
@@ -219,7 +216,7 @@ export async function run(argv, ctx) {
219
216
  const runtime = { useDocker: args.docker, runnerDir: null };
220
217
  await Promise.all([
221
218
  ensureCheckout(client, tenant, dir, env),
222
- prefetchRuntime(client, devArgs, env, runtime),
219
+ prefetchRuntime(client, devArgs, env, runtime, ctx),
223
220
  ]);
224
221
 
225
222
  // 5. dev — native by default (F3), Docker on --docker or the fallback
@@ -418,11 +415,16 @@ async function preflight(ctx, env) {
418
415
  * Prefetch the runner (C1) so it's overlapped with checkout instead of paid
419
416
  * for serially afterward: the native renderer artifact by default (F3 — no
420
417
  * Docker prerequisite), or the Docker registry pull credential on --docker.
421
- * On a native fetch failure, falls back to Docker automatically — the same
422
- * fallback `tot dev` uses (dev.mjs#runStandalone) flipping
423
- * `runtime.useDocker` so the caller's subsequent dev step picks it up.
418
+ *
419
+ * On a native (entitled-artifact) fetch failure the runtime stays NATIVE: it
420
+ * falls back to the PUBLIC npm runner (@tokenoftrust/storefront-runner) the
421
+ * SAME renderer bits the entitled artifact ships, just delivered over
422
+ * public npm instead of a signed URL — so `tot dev`/`tot start` never require
423
+ * Docker just because `dev_renderer_artifact` isn't configured on a deployment.
424
+ * Docker is the LAST resort, only when the public runner is also unreachable
425
+ * (offline) — flipping `runtime.useDocker` so the caller's dev step picks it up.
424
426
  */
425
- async function prefetchRuntime(client, devArgs, env, runtime) {
427
+ async function prefetchRuntime(client, devArgs, env, runtime, ctx) {
426
428
  if (runtime.useDocker) {
427
429
  await prefetchDockerLogin(client, devArgs, env);
428
430
  return;
@@ -431,9 +433,15 @@ async function prefetchRuntime(client, devArgs, env, runtime) {
431
433
  runtime.runnerDir = await ensureRendererArtifact(devArgs, { client });
432
434
  } catch (e) {
433
435
  if (!(e instanceof NativeArtifactUnavailableError)) throw e;
434
- console.log(` ~ native runtime unavailable (${e.message}) falling back to the Docker runner.`);
435
- runtime.useDocker = true;
436
- await prefetchDockerLogin(client, devArgs, env);
436
+ // Entitled artifact unavailable — stay native on the public runner (no Docker).
437
+ try {
438
+ console.log(` ~ entitled renderer unavailable (${e.message}) using the public runner (no Docker).`);
439
+ runtime.runnerDir = await ensureSampleRenderer(devArgs, ctx, { env });
440
+ } catch (e2) {
441
+ console.log(` ~ public runner unavailable (${e2?.message || e2}) — falling back to the Docker runner.`);
442
+ runtime.useDocker = true;
443
+ await prefetchDockerLogin(client, devArgs, env);
444
+ }
437
445
  }
438
446
  }
439
447
 
@@ -493,8 +501,7 @@ function noStoresError({ session, baseUrl, listErr }) {
493
501
  {
494
502
  next:
495
503
  "if you were just invited, it may still be propagating — try again in a minute; " +
496
- "otherwise ask your Token of Trust contact for a store invite (see `tot whoami`), " +
497
- "or `tot start --sample` for the free local preview",
504
+ "otherwise ask your Token of Trust contact for a store invite (see `tot whoami`)",
498
505
  },
499
506
  );
500
507
  }
@@ -7,9 +7,8 @@
7
7
  * 3. report back — reconcile result + compliance verdict + the preview URL — from the MCP.
8
8
  *
9
9
  * This is submit-for-PREVIEW, not ship-to-live (`change_accept` / a future `tot ship`
10
- * is the separate ship gate). Step 3 calls the MCP `preview_status` read-back
11
- * (~/.tot-mcp/handoffs/2026-07-09-tot-mcp-tot-submit-contract.md): given the commit
12
- * just pushed it returns { status, reconcile, compliance, previewUrl } and we poll it
10
+ * is the separate ship gate). Step 3 calls the MCP `preview_status` read-back:
11
+ * given the commit just pushed it returns { status, reconcile, compliance, previewUrl } and we poll it
13
12
  * while reconcile is pending. If that tool isn't present (older MCP) the command still
14
13
  * validates + pushes and reports "reconcile pending" — degrading visibly, never a crash.
15
14
  *
@@ -231,8 +230,8 @@ const CHECK_GLYPH = { pass: "✓", fail: "✗", warn: "⚠", skip: "~" };
231
230
 
232
231
  /**
233
232
  * Print one per-rule compliance check: id/label, required-ness, why it didn't
234
- * pass (detail), and a concrete fix suggestion (hint) when there is one. This is
235
- * the moat over a bare pass/fail — an agent (or a human) reading `tot submit`
233
+ * pass (detail), and a concrete fix suggestion (hint) when there is one. This
234
+ * beats a bare pass/fail — an agent (or a human) reading `tot submit`
236
235
  * output should know exactly what to change and why, with no dashboard round-trip.
237
236
  */
238
237
  function reportComplianceCheck(c) {
package/src/sample.mjs CHANGED
@@ -110,7 +110,12 @@ export function scaffoldSample(destDir, { force = false, log = () => {} } = {})
110
110
 
111
111
  const template = sampleTemplateDir();
112
112
  if (!existsSync(template)) {
113
- throw new Error(`bundled sample template missing at ${template} — is the package built/installed correctly?`);
113
+ const err = new Error(
114
+ "the sample store isn't available in this release yet — it's coming soon. " +
115
+ "To build a real store now: `tot login --code <invite>` then `tot start`.",
116
+ );
117
+ err.code = "SAMPLE_UNAVAILABLE";
118
+ throw err;
114
119
  }
115
120
 
116
121
  mkdirSync(dir, { recursive: true });
@@ -1,152 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <link rel="icon" type="image/png" href="/tenants/giantvapes/logo-wordmark.png">
7
- <link rel="stylesheet" href="/tenants/giantvapes/themes/giant-navy.css">
8
- <link rel="stylesheet" href="/tenants/giantvapes/pages/mkt.css">
9
- <!--PAGE_HEAD-->
10
- </head>
11
- <body>
12
- <a class="skip-link" href="#main">Skip to main content</a>
13
-
14
- <!-- Top FDA warning bar -->
15
- <div class="topbar-warning"><p>WARNING: This product contains nicotine. Nicotine is an addictive chemical.</p></div>
16
-
17
- <!-- Announcement: scrolling marquee -->
18
- <div class="announce-marquee" aria-label="Free US shipping on orders over $100">
19
- <div class="announce-marquee__track" aria-hidden="true">
20
- <span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span>
21
- <span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span><span>FREE U.S. Shipping on Orders Over $100!</span>
22
- </div>
23
- </div>
24
-
25
- <!-- Utility nav -->
26
- <div class="utility-nav">
27
- <div class="container">
28
- <ul>
29
- <li><a href="/blogs/news">News</a></li>
30
- <li><a href="/pages/about-us">About</a></li>
31
- <li><a href="/pages/contact-us">Contact</a></li>
32
- <li><a href="/pages/faq">FAQ</a></li>
33
- <li><a href="/pages/order-tracking">Track Order</a></li>
34
- </ul>
35
- <div class="utility-nav__right">
36
- <span class="sel">English</span>
37
- <span class="sel">United States (USD $)</span>
38
- <span class="social">
39
- <a href="https://instagram.com/giantvapes" aria-label="Instagram" rel="noopener"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="1.1"/></svg></a>
40
- <a href="https://facebook.com/giantvapes" aria-label="Facebook" rel="noopener"><svg viewBox="0 0 24 24"><path d="M14 8h2V5h-2a4 4 0 0 0-4 4v2H8v3h2v6h3v-6h2.2l.8-3H13V9a1 1 0 0 1 1-1z"/></svg></a>
41
- </span>
42
- </div>
43
- </div>
44
- </div>
45
-
46
- <!-- Header -->
47
- <header class="site-header">
48
- <div class="container header-row">
49
- <a class="brand" href="/" aria-label="Giant Vapes home"><img src="/tenants/giantvapes/logo-wordmark.png" alt="Giant Vapes" width="200" height="106"></a>
50
- <form class="header-search" action="/search" method="get" role="search">
51
- <label class="sr-only" for="hdr-q">Search for anything</label>
52
- <input id="hdr-q" type="search" name="q" placeholder="Search e-liquids, disposables, hardware" autocomplete="off">
53
- <button type="submit" aria-label="Search"><svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg></button>
54
- </form>
55
- <div class="header-actions">
56
- <a href="/account" aria-label="Account"><svg viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4.4 3.6-7 8-7s8 2.6 8 7"/></svg></a>
57
- <a class="cart" href="/cart" aria-label="Cart"><svg viewBox="0 0 24 24"><path d="M6 6h15l-1.5 9h-12z"/><circle cx="9" cy="20" r="1.4"/><circle cx="18" cy="20" r="1.4"/><path d="M6 6L5 3H2"/></svg><span class="count">0</span></a>
58
- <button class="hamburger" id="hamburger" aria-label="Toggle navigation menu" aria-expanded="false" aria-controls="primaryNav"><span></span><span></span><span></span></button>
59
- </div>
60
- </div>
61
- <nav class="primary-nav-bar" aria-label="Primary">
62
- <div class="container">
63
- <nav class="primary-nav" id="primaryNav">
64
- <ul>
65
- <li><a href="/collections/all">E-Liquid<span class="caret">▾</span></a></li>
66
- <li><a href="/collections/salt-nic">Salt Nic</a></li>
67
- <li><a href="/collections/all-disposables">Disposables<span class="caret">▾</span></a></li>
68
- <li><a href="/collections/vaporesso">Hardware<span class="caret">▾</span></a></li>
69
- <li><a href="/collections/nicotine-pouches">Nic Pouches</a></li>
70
- <li><a href="/collections/new-arrivals">New Arrivals</a></li>
71
- <li><a class="is-flag" href="/collections/clearance">Clearance<span class="new-badge">SALE</span></a></li>
72
- <li><a href="/collections/all">Brands<span class="caret">▾</span></a></li>
73
- </ul>
74
- </nav>
75
- </div>
76
- </nav>
77
- </header>
78
-
79
- <!--PAGE_BODY-->
80
-
81
- <!-- Compliance strip -->
82
- <div class="compliance-strip">
83
- <div class="container"><p>WARNING: This product contains nicotine. Nicotine is an addictive chemical.</p></div>
84
- </div>
85
-
86
- <!-- Footer -->
87
- <footer class="site-footer">
88
- <div class="container">
89
- <div class="footer-grid">
90
- <div class="footer-brand">
91
- <img src="/tenants/giantvapes/logo-wordmark.png" alt="Giant Vapes" width="200" height="106">
92
- <p>Premium e-liquid, salts, and disposables — shipped fast.<br>Serving vapers online since 2013.</p>
93
- </div>
94
- <div class="footer-col">
95
- <h4>Shop</h4>
96
- <ul>
97
- <li><a href="/collections/all">E-Liquid</a></li>
98
- <li><a href="/collections/salt-nic">Salt Nic</a></li>
99
- <li><a href="/collections/all-disposables">Disposables</a></li>
100
- <li><a href="/collections/vaporesso">Hardware</a></li>
101
- <li><a href="/collections/nicotine-pouches">Nic Pouches</a></li>
102
- <li><a href="/collections/clearance">Clearance</a></li>
103
- </ul>
104
- </div>
105
- <div class="footer-col">
106
- <h4>Support</h4>
107
- <ul>
108
- <li><a href="/search">Search</a></li>
109
- <li><a href="/pages/about-us">About Us</a></li>
110
- <li><a href="/pages/contact-us">Contact Us</a></li>
111
- <li><a href="/pages/faq">FAQ</a></li>
112
- <li><a href="/pages/order-tracking">Order Tracking</a></li>
113
- <li><a href="/blogs/news">Blog</a></li>
114
- </ul>
115
- </div>
116
- <div class="footer-col">
117
- <h4>Company</h4>
118
- <ul>
119
- <li><a href="/pages/shipping-returns">Shipping &amp; Returns</a></li>
120
- <li><a href="/pages/privacy-policy">Privacy Policy</a></li>
121
- <li><a href="/pages/giant-distribution">Wholesale</a></li>
122
- </ul>
123
- <form class="footer-news" action="/api/newsletter" method="post">
124
- <input type="hidden" name="source" value="footer">
125
- <label class="sr-only" for="foot-email">Email</label>
126
- <input id="foot-email" type="email" name="email" placeholder="Email" required>
127
- <button type="submit" aria-label="Subscribe">→</button>
128
- </form>
129
- <div class="pay-badges" aria-label="Accepted payments">
130
- <span>AMEX</span><span>Discover</span><span>Mastercard</span><span>Visa</span><span>PayPal</span>
131
- </div>
132
- </div>
133
- </div>
134
- <div class="footer-warning">
135
- <p><strong>WARNING:</strong> This product contains nicotine. Nicotine is an addictive chemical. Products intended for adults of legal smoking age (21+) only.</p>
136
- </div>
137
- <div class="footer-bottom">
138
- <p>© Giant Vapes, LLC. All rights reserved.</p>
139
- <p>Must be 21 or older to purchase. Not for sale to minors.</p>
140
- </div>
141
- </div>
142
- </footer>
143
-
144
- <script>
145
- (function () {
146
- var burger = document.getElementById('hamburger');
147
- var nav = document.getElementById('primaryNav');
148
- if (burger && nav) burger.addEventListener('click', function () { var o = nav.classList.toggle('open'); burger.setAttribute('aria-expanded', o ? 'true' : 'false'); });
149
- })();
150
- </script>
151
- </body>
152
- </html>
@@ -1,94 +0,0 @@
1
- {
2
- "announcement": "FREE U.S. Shipping on Orders Over $100!",
3
- "nav": [
4
- {
5
- "label": "E-Liquid",
6
- "href": "/collections/fruity-e-liquids",
7
- "children": [
8
- {
9
- "label": "Fruity E-Liquids",
10
- "href": "/collections/fruity-e-liquids"
11
- },
12
- {
13
- "label": "Nicotine Salts",
14
- "href": "/collections/nicotine-salts"
15
- }
16
- ]
17
- },
18
- {
19
- "label": "Fruity E-Liquids",
20
- "href": "/collections/fruity-e-liquids"
21
- },
22
- {
23
- "label": "Nicotine Salts",
24
- "href": "/collections/nicotine-salts"
25
- },
26
- {
27
- "label": "Disposables",
28
- "href": "/collections/all-disposables"
29
- },
30
- {
31
- "label": "About",
32
- "href": "/about"
33
- }
34
- ],
35
- "footer": {
36
- "tagline": "Premium e-liquid, salts, and disposables — shipped fast.",
37
- "columns": [
38
- {
39
- "title": "Shop",
40
- "links": [
41
- {
42
- "label": "Fruity E-Liquids",
43
- "href": "/collections/fruity-e-liquids"
44
- },
45
- {
46
- "label": "Nicotine Salts",
47
- "href": "/collections/nicotine-salts"
48
- },
49
- {
50
- "label": "Disposables",
51
- "href": "/collections/all-disposables"
52
- },
53
- {
54
- "label": "Search",
55
- "href": "/search"
56
- }
57
- ]
58
- },
59
- {
60
- "title": "Company",
61
- "links": [
62
- {
63
- "label": "About",
64
- "href": "/about"
65
- },
66
- {
67
- "label": "Shipping & Returns",
68
- "href": "/shipping-returns"
69
- },
70
- {
71
- "label": "Privacy",
72
- "href": "/privacy"
73
- }
74
- ]
75
- }
76
- ],
77
- "social": [
78
- {
79
- "label": "Instagram",
80
- "href": "https://instagram.com"
81
- },
82
- {
83
- "label": "Newsletter",
84
- "href": "#newsletter"
85
- }
86
- ]
87
- },
88
- "disclaimer": "<p>This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a><p></p>\n<p>Giant Vapes will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of these products. Please have a great understanding of the items you are using and how to store, use and care for your products properly. Terms and Conditions.</p>\n<p><b>WARNING:</b> This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a></p>\n<p>This consumable nicotine product is not eligible for return, refund or exchange.</p>",
89
- "disclaimers": {
90
- "Vape Juice": "<p>This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a><p></p>\n<p>Giant Vapes will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of these products. Please have a great understanding of the items you are using and how to store, use and care for your products properly. Terms and Conditions.</p>\n<p><b>WARNING:</b> This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a></p>\n<p>This consumable nicotine product is not eligible for return, refund or exchange.</p>",
91
- "Nicotine Salt": "<p><b>WARNING: Do not use this product in sub-ohm tanks or with sub-ohm coils.</b> This eliquid contains nicotine salt and has a substantially higher amount of nicotine per milliliter than other eliquids. This eliquid is designed <b>only</b> for use with high-resistance coils (1.0 ohm or higher) and ultra low output/low wattage vaping devices.<p></p>\n<p>This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a><p></p>\n<p>Giant Vapes will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of these products. Please have a great understanding of the items you are using and how to store, use and care for your products properly. Terms and Conditions.</p>\n<p><b>WARNING:</b> This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a></p>\n<p>This consumable nicotine product is not eligible for return, refund or exchange.</p>",
92
- "Vape Disposable": "<p>There is always risk involved when using tobacco and nicotine products and/or rechargeable batteries, at any time and under any circumstances. Giant Vapes is not held responsible for any damage for any modification of the batteries, chargers, devices and other products that are sold on GiantVapes.com.</p>\n<p>Please Note: There is always risk involved when using rechargeable batteries at anytime and under any circumstances. Giant Vapes, LLC is not held responsible for any damage for any modification of the batteries, chargers, devices and other products that are sold on GiantVapes.com.</p>\n<p>Giant Vapes, LLC will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of a Li-ion (Lithium-ion), LiPo (Lithium-ion Polymer) nor any rechargeable battery/batteries as well as chargers. Please have a great understanding of the batteries/chargers you are using and how to care for them properly. You can see a list of our recommendations for proper handling of rechargeable batteries in our terms and conditions</p>\n<p>This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a><p></p>\n<p>Giant Vapes will not be held liable for any injury, damage, or defect, permanent or temporary that may be caused by the improper use of these products. Please have a great understanding of the items you are using and how to store, use and care for your products properly. Terms and Conditions.</p>\n<p><b>WARNING:</b> This product can expose you to chemicals including Nicotine, which is known to the State of California to cause birth defects or other reproductive harm. For more information go to <a href=\"http://www.p65warnings.ca.gov\">www.P65Warnings.ca.gov</a></p>"
93
- }
94
- }