@proveanything/smartlinks 2.0.0-alpha.1 → 2.0.0-alpha.2
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/docs/API_SUMMARY.md +1 -1
- package/dist/docs/deploying-apps.md +86 -35
- package/docs/API_SUMMARY.md +1 -1
- package/docs/deploying-apps.md +86 -35
- package/package.json +1 -1
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -20,20 +20,30 @@ This guide covers registration and how to wire it into your build.
|
|
|
20
20
|
|
|
21
21
|
Deploying touches two different locations — keep them distinct:
|
|
22
22
|
|
|
23
|
-
1. **The install endpoint (API host)** — *where you register*.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
1. **The install endpoint (API host)** — *where you register*. On the **main SaaS this is
|
|
24
|
+
`https://smartlinks.app`** (the API lives under `/api/v1` — the same base your app already
|
|
25
|
+
passes to `initializeApi`). A client's isolated (VPC) environment has its **own** host; you
|
|
26
|
+
install into it by calling that host. This is the value that varies per deployment.
|
|
27
|
+
2. **The bundle CDN** — *where your built files are actually served from*, which you pass at
|
|
28
|
+
registration as **`bundleBaseUrl`**. **This depends on the channel:**
|
|
29
|
+
- **`dev` (Lovable):** your files are served by **Lovable at your published app URL** — that
|
|
30
|
+
URL is your dev `bundleBaseUrl`. Lovable *is* the CDN for dev; nothing is uploaded to
|
|
31
|
+
SmartLinks.
|
|
32
|
+
- **`prod`:** files are published to the SmartLinks app CDN at
|
|
33
|
+
`https://smartlinks.app/apps/{appId}/{version}/…` by your prod deploy step; that base is
|
|
34
|
+
your prod `bundleBaseUrl`.
|
|
27
35
|
|
|
28
36
|
```
|
|
29
|
-
https://smartlinks.app/apps/{appId}/{version}/app.manifest.json
|
|
30
|
-
https://smartlinks.app/apps/{appId}/{version}/widgets-<hash>.umd.js
|
|
37
|
+
https://smartlinks.app/apps/{appId}/{version}/app.manifest.json # prod layout
|
|
31
38
|
https://smartlinks.app/apps/{appId}/{version}/functions.umd.js
|
|
32
39
|
```
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
Always pass `bundleBaseUrl` explicitly so it keeps working if a location changes.
|
|
42
|
+
|
|
43
|
+
> **Who publishes the bundles?** The platform does **not** fetch or mirror them for you —
|
|
44
|
+
> `bundleBaseUrl` must already serve the files at registration time. For `dev` that's Lovable
|
|
45
|
+
> (on Publish); for `prod` that's your own CDN deploy step. Registration records *where* the
|
|
46
|
+
> bundles are + the validated manifest; it does not host anything.
|
|
37
47
|
|
|
38
48
|
## Environments & the app registry
|
|
39
49
|
|
|
@@ -72,26 +82,36 @@ and exercise a build before it reaches `prod`.
|
|
|
72
82
|
|
|
73
83
|
## Deploy keys
|
|
74
84
|
|
|
75
|
-
Registration is authenticated by a **deploy key** — not a user login — scoped to the
|
|
76
|
-
|
|
77
|
-
what it was allowed to touch.
|
|
85
|
+
Registration is authenticated by a **deploy key** — not a user login — scoped to the channels
|
|
86
|
+
it may write. Security comes from the *scope*: a leaked key can only do what its scope allows.
|
|
78
87
|
|
|
79
|
-
| Key |
|
|
80
|
-
|
|
81
|
-
| **Dev key** |
|
|
82
|
-
| **Prod master key** | your Cloud Build
|
|
83
|
-
| **Per-app key** *(future)* |
|
|
88
|
+
| Key | Where to keep it | May write | If it leaks |
|
|
89
|
+
|---|---|---|---|
|
|
90
|
+
| **Dev key** | a **Lovable workspace Build Secret** (below) | `dev` channel, **any app in the environment** | someone can register/overwrite `dev` releases — which are served only to test collections — but **never** `beta`/`prod` |
|
|
91
|
+
| **Prod master key** | your CI/Cloud Build secret store **only** | all channels | full control — so keep it out of app source entirely |
|
|
92
|
+
| **Per-app key** *(future)* | provisioned per app | one specific app | scoped to that one app |
|
|
93
|
+
|
|
94
|
+
**Keep the dev key in Lovable Build Secrets — do not commit it.** Lovable exposes
|
|
95
|
+
**workspace-level Build Secrets** shared across every project in the workspace: set the dev key
|
|
96
|
+
there **once** and every microapp inherits it, nothing is committed, and there's a single value
|
|
97
|
+
to rotate. (An earlier draft of this guide said to put the key in app source — don't; use Build
|
|
98
|
+
Secrets.)
|
|
84
99
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
100
|
+
**Minting (current state, 2.0.0-alpha):** the `dev` and `prod` keys are **shared secrets
|
|
101
|
+
configured on the SmartLinks backend** — one `dev` key and one `prod` key covering all
|
|
102
|
+
first-party apps. There is **no self-service minting UI yet**: ask the platform owner for the
|
|
103
|
+
`dev` key and put it in your workspace Build Secret. Per-app keys, self-service minting, and
|
|
104
|
+
rotation are planned; rotating the shared `dev` key just means updating the one Build Secret
|
|
105
|
+
(registered releases are unaffected — the key authorizes *writes*, it isn't stored on releases).
|
|
106
|
+
|
|
107
|
+
Present the key in the `x-smartlinks-deploy-key` header.
|
|
88
108
|
|
|
89
109
|
---
|
|
90
110
|
|
|
91
111
|
## The registration endpoint
|
|
92
112
|
|
|
93
113
|
```
|
|
94
|
-
POST https
|
|
114
|
+
POST https://smartlinks.app/api/v1/apps/{appId}/releases # main SaaS; a VPC env uses its own host
|
|
95
115
|
x-smartlinks-deploy-key: <your deploy key>
|
|
96
116
|
Content-Type: application/json
|
|
97
117
|
```
|
|
@@ -124,6 +144,15 @@ Each validation error is `{ code, message, path }`, e.g.:
|
|
|
124
144
|
]}
|
|
125
145
|
```
|
|
126
146
|
|
|
147
|
+
### Re-registering & version collisions
|
|
148
|
+
|
|
149
|
+
Registration is an **upsert keyed by (app, channel)** — the newest registration becomes that
|
|
150
|
+
channel's live release. Registering again **overwrites** it (last write wins); there is **no**
|
|
151
|
+
version-collision error even if `meta.version` is unchanged. So re-publishing to `dev` without
|
|
152
|
+
bumping the version is a normal, intentional overwrite — which is what you want on `dev`. (A
|
|
153
|
+
stricter `prod` policy that rejects a duplicate `version` may come later; it isn't enforced
|
|
154
|
+
today.)
|
|
155
|
+
|
|
127
156
|
### What gets validated
|
|
128
157
|
|
|
129
158
|
- `manifest.meta.appId` must match the `{appId}` in the URL.
|
|
@@ -145,24 +174,36 @@ so a bad install fails the publish.
|
|
|
145
174
|
import { readFileSync } from 'node:fs'
|
|
146
175
|
import { execSync } from 'node:child_process'
|
|
147
176
|
|
|
148
|
-
const API
|
|
149
|
-
const KEY
|
|
150
|
-
const CHANNEL
|
|
177
|
+
const API = process.env.SMARTLINKS_API || 'https://smartlinks.app' // a VPC env: set to its host
|
|
178
|
+
const KEY = process.env.SMARTLINKS_DEPLOY_KEY // Lovable Build Secret (dev) / CI secret (prod)
|
|
179
|
+
const CHANNEL = process.env.SMARTLINKS_CHANNEL // 'dev' | 'beta' | 'prod'; UNSET ⇒ don't register
|
|
180
|
+
|
|
181
|
+
// --- Gate: only register when this build is meant to ---
|
|
182
|
+
// A preview / live-edit build (no channel) skips quietly so it never fails. A build that
|
|
183
|
+
// declares a channel but has no key is a hard error IF it's prod; dev skips quietly.
|
|
184
|
+
if (!CHANNEL) {
|
|
185
|
+
console.log('ℹ︎ SmartLinks: SMARTLINKS_CHANNEL unset — skipping release registration (preview build).')
|
|
186
|
+
process.exit(0)
|
|
187
|
+
}
|
|
188
|
+
if (!KEY) {
|
|
189
|
+
if (CHANNEL === 'prod') { console.error('❌ prod build but SMARTLINKS_DEPLOY_KEY is missing'); process.exit(1) }
|
|
190
|
+
console.log(`ℹ︎ SmartLinks: no deploy key for "${CHANNEL}" — skipping registration.`)
|
|
191
|
+
process.exit(0)
|
|
192
|
+
}
|
|
151
193
|
|
|
152
194
|
const manifest = JSON.parse(readFileSync('dist/app.manifest.json', 'utf8'))
|
|
153
195
|
const appId = manifest.meta.appId
|
|
154
196
|
const version = manifest.meta.version
|
|
155
197
|
const gitHash = (() => { try { return execSync('git rev-parse --short HEAD').toString().trim() } catch { return null } })()
|
|
198
|
+
// dev: your published Lovable URL; prod: the SmartLinks CDN base. Set SMARTLINKS_BUNDLE_BASE_URL.
|
|
199
|
+
const bundleBaseUrl = process.env.SMARTLINKS_BUNDLE_BASE_URL || `https://smartlinks.app/apps/${appId}/${version}`
|
|
156
200
|
|
|
157
201
|
const res = await fetch(`${API}/api/v1/apps/${appId}/releases`, {
|
|
158
202
|
method: 'POST',
|
|
159
203
|
headers: { 'content-type': 'application/json', 'x-smartlinks-deploy-key': KEY },
|
|
160
204
|
body: JSON.stringify({
|
|
161
|
-
channel: CHANNEL,
|
|
162
|
-
|
|
163
|
-
build: { at: new Date().toISOString(), gitHash, builder: CHANNEL === 'dev' ? 'lovable' : 'cloudbuild' },
|
|
164
|
-
manifest,
|
|
165
|
-
bundleBaseUrl: `https://smartlinks.app/apps/${appId}/${version}`,
|
|
205
|
+
channel: CHANNEL, version, manifest, bundleBaseUrl,
|
|
206
|
+
build: { at: new Date().toISOString(), gitHash, builder: CHANNEL === 'dev' ? 'lovable' : 'ci' },
|
|
166
207
|
}),
|
|
167
208
|
})
|
|
168
209
|
|
|
@@ -175,7 +216,7 @@ if (!res.ok || !body.ok) {
|
|
|
175
216
|
console.log(`✅ Registered ${appId}@${version} on "${CHANNEL}" — functions: ${(body.functions || []).join(', ') || 'none'}`)
|
|
176
217
|
```
|
|
177
218
|
|
|
178
|
-
Wire it after your bundle build/hash step
|
|
219
|
+
Wire it after your bundle build/hash step:
|
|
179
220
|
|
|
180
221
|
```jsonc
|
|
181
222
|
// package.json
|
|
@@ -185,9 +226,19 @@ Wire it after your bundle build/hash step, e.g.:
|
|
|
185
226
|
}
|
|
186
227
|
```
|
|
187
228
|
|
|
188
|
-
|
|
189
|
-
`SMARTLINKS_CHANNEL=dev`.
|
|
190
|
-
- **Prod (Cloud Build)** runs the same with the **prod key** and `SMARTLINKS_CHANNEL=prod`.
|
|
229
|
+
Registration is gated by **`SMARTLINKS_CHANNEL`**, so the three Lovable build types behave correctly:
|
|
191
230
|
|
|
192
|
-
|
|
193
|
-
|
|
231
|
+
| Build | `SMARTLINKS_CHANNEL` | Result |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| **Preview / live-edit** | unset | **skips quietly** — never registers, never fails |
|
|
234
|
+
| **Dev (Publish)** | `dev` | registers to `dev` with the workspace Build-Secret key + your Lovable `SMARTLINKS_BUNDLE_BASE_URL` |
|
|
235
|
+
| **Prod (CI)** | `prod` | registers to `prod` with the prod key; a missing key **hard-fails** |
|
|
236
|
+
|
|
237
|
+
The gate is `SMARTLINKS_CHANNEL`, so **set it only where you want a release** — i.e. on the
|
|
238
|
+
Publish/CI build, not on preview. If your host exposes a publish-only signal (an env var it sets
|
|
239
|
+
only on Publish), key `SMARTLINKS_CHANNEL` off that; otherwise set it in the Publish build's env
|
|
240
|
+
and leave it unset for preview. That one variable is the difference between "this build ships a
|
|
241
|
+
release" and "this build is just a preview."
|
|
242
|
+
|
|
243
|
+
That's it: a real Publish validates + registers your app (a broken manifest or function stops
|
|
244
|
+
the deploy with an actionable error), while preview builds stay quiet.
|
package/docs/API_SUMMARY.md
CHANGED
package/docs/deploying-apps.md
CHANGED
|
@@ -20,20 +20,30 @@ This guide covers registration and how to wire it into your build.
|
|
|
20
20
|
|
|
21
21
|
Deploying touches two different locations — keep them distinct:
|
|
22
22
|
|
|
23
|
-
1. **The install endpoint (API host)** — *where you register*.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
1. **The install endpoint (API host)** — *where you register*. On the **main SaaS this is
|
|
24
|
+
`https://smartlinks.app`** (the API lives under `/api/v1` — the same base your app already
|
|
25
|
+
passes to `initializeApi`). A client's isolated (VPC) environment has its **own** host; you
|
|
26
|
+
install into it by calling that host. This is the value that varies per deployment.
|
|
27
|
+
2. **The bundle CDN** — *where your built files are actually served from*, which you pass at
|
|
28
|
+
registration as **`bundleBaseUrl`**. **This depends on the channel:**
|
|
29
|
+
- **`dev` (Lovable):** your files are served by **Lovable at your published app URL** — that
|
|
30
|
+
URL is your dev `bundleBaseUrl`. Lovable *is* the CDN for dev; nothing is uploaded to
|
|
31
|
+
SmartLinks.
|
|
32
|
+
- **`prod`:** files are published to the SmartLinks app CDN at
|
|
33
|
+
`https://smartlinks.app/apps/{appId}/{version}/…` by your prod deploy step; that base is
|
|
34
|
+
your prod `bundleBaseUrl`.
|
|
27
35
|
|
|
28
36
|
```
|
|
29
|
-
https://smartlinks.app/apps/{appId}/{version}/app.manifest.json
|
|
30
|
-
https://smartlinks.app/apps/{appId}/{version}/widgets-<hash>.umd.js
|
|
37
|
+
https://smartlinks.app/apps/{appId}/{version}/app.manifest.json # prod layout
|
|
31
38
|
https://smartlinks.app/apps/{appId}/{version}/functions.umd.js
|
|
32
39
|
```
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
41
|
+
Always pass `bundleBaseUrl` explicitly so it keeps working if a location changes.
|
|
42
|
+
|
|
43
|
+
> **Who publishes the bundles?** The platform does **not** fetch or mirror them for you —
|
|
44
|
+
> `bundleBaseUrl` must already serve the files at registration time. For `dev` that's Lovable
|
|
45
|
+
> (on Publish); for `prod` that's your own CDN deploy step. Registration records *where* the
|
|
46
|
+
> bundles are + the validated manifest; it does not host anything.
|
|
37
47
|
|
|
38
48
|
## Environments & the app registry
|
|
39
49
|
|
|
@@ -72,26 +82,36 @@ and exercise a build before it reaches `prod`.
|
|
|
72
82
|
|
|
73
83
|
## Deploy keys
|
|
74
84
|
|
|
75
|
-
Registration is authenticated by a **deploy key** — not a user login — scoped to the
|
|
76
|
-
|
|
77
|
-
what it was allowed to touch.
|
|
85
|
+
Registration is authenticated by a **deploy key** — not a user login — scoped to the channels
|
|
86
|
+
it may write. Security comes from the *scope*: a leaked key can only do what its scope allows.
|
|
78
87
|
|
|
79
|
-
| Key |
|
|
80
|
-
|
|
81
|
-
| **Dev key** |
|
|
82
|
-
| **Prod master key** | your Cloud Build
|
|
83
|
-
| **Per-app key** *(future)* |
|
|
88
|
+
| Key | Where to keep it | May write | If it leaks |
|
|
89
|
+
|---|---|---|---|
|
|
90
|
+
| **Dev key** | a **Lovable workspace Build Secret** (below) | `dev` channel, **any app in the environment** | someone can register/overwrite `dev` releases — which are served only to test collections — but **never** `beta`/`prod` |
|
|
91
|
+
| **Prod master key** | your CI/Cloud Build secret store **only** | all channels | full control — so keep it out of app source entirely |
|
|
92
|
+
| **Per-app key** *(future)* | provisioned per app | one specific app | scoped to that one app |
|
|
93
|
+
|
|
94
|
+
**Keep the dev key in Lovable Build Secrets — do not commit it.** Lovable exposes
|
|
95
|
+
**workspace-level Build Secrets** shared across every project in the workspace: set the dev key
|
|
96
|
+
there **once** and every microapp inherits it, nothing is committed, and there's a single value
|
|
97
|
+
to rotate. (An earlier draft of this guide said to put the key in app source — don't; use Build
|
|
98
|
+
Secrets.)
|
|
84
99
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
100
|
+
**Minting (current state, 2.0.0-alpha):** the `dev` and `prod` keys are **shared secrets
|
|
101
|
+
configured on the SmartLinks backend** — one `dev` key and one `prod` key covering all
|
|
102
|
+
first-party apps. There is **no self-service minting UI yet**: ask the platform owner for the
|
|
103
|
+
`dev` key and put it in your workspace Build Secret. Per-app keys, self-service minting, and
|
|
104
|
+
rotation are planned; rotating the shared `dev` key just means updating the one Build Secret
|
|
105
|
+
(registered releases are unaffected — the key authorizes *writes*, it isn't stored on releases).
|
|
106
|
+
|
|
107
|
+
Present the key in the `x-smartlinks-deploy-key` header.
|
|
88
108
|
|
|
89
109
|
---
|
|
90
110
|
|
|
91
111
|
## The registration endpoint
|
|
92
112
|
|
|
93
113
|
```
|
|
94
|
-
POST https
|
|
114
|
+
POST https://smartlinks.app/api/v1/apps/{appId}/releases # main SaaS; a VPC env uses its own host
|
|
95
115
|
x-smartlinks-deploy-key: <your deploy key>
|
|
96
116
|
Content-Type: application/json
|
|
97
117
|
```
|
|
@@ -124,6 +144,15 @@ Each validation error is `{ code, message, path }`, e.g.:
|
|
|
124
144
|
]}
|
|
125
145
|
```
|
|
126
146
|
|
|
147
|
+
### Re-registering & version collisions
|
|
148
|
+
|
|
149
|
+
Registration is an **upsert keyed by (app, channel)** — the newest registration becomes that
|
|
150
|
+
channel's live release. Registering again **overwrites** it (last write wins); there is **no**
|
|
151
|
+
version-collision error even if `meta.version` is unchanged. So re-publishing to `dev` without
|
|
152
|
+
bumping the version is a normal, intentional overwrite — which is what you want on `dev`. (A
|
|
153
|
+
stricter `prod` policy that rejects a duplicate `version` may come later; it isn't enforced
|
|
154
|
+
today.)
|
|
155
|
+
|
|
127
156
|
### What gets validated
|
|
128
157
|
|
|
129
158
|
- `manifest.meta.appId` must match the `{appId}` in the URL.
|
|
@@ -145,24 +174,36 @@ so a bad install fails the publish.
|
|
|
145
174
|
import { readFileSync } from 'node:fs'
|
|
146
175
|
import { execSync } from 'node:child_process'
|
|
147
176
|
|
|
148
|
-
const API
|
|
149
|
-
const KEY
|
|
150
|
-
const CHANNEL
|
|
177
|
+
const API = process.env.SMARTLINKS_API || 'https://smartlinks.app' // a VPC env: set to its host
|
|
178
|
+
const KEY = process.env.SMARTLINKS_DEPLOY_KEY // Lovable Build Secret (dev) / CI secret (prod)
|
|
179
|
+
const CHANNEL = process.env.SMARTLINKS_CHANNEL // 'dev' | 'beta' | 'prod'; UNSET ⇒ don't register
|
|
180
|
+
|
|
181
|
+
// --- Gate: only register when this build is meant to ---
|
|
182
|
+
// A preview / live-edit build (no channel) skips quietly so it never fails. A build that
|
|
183
|
+
// declares a channel but has no key is a hard error IF it's prod; dev skips quietly.
|
|
184
|
+
if (!CHANNEL) {
|
|
185
|
+
console.log('ℹ︎ SmartLinks: SMARTLINKS_CHANNEL unset — skipping release registration (preview build).')
|
|
186
|
+
process.exit(0)
|
|
187
|
+
}
|
|
188
|
+
if (!KEY) {
|
|
189
|
+
if (CHANNEL === 'prod') { console.error('❌ prod build but SMARTLINKS_DEPLOY_KEY is missing'); process.exit(1) }
|
|
190
|
+
console.log(`ℹ︎ SmartLinks: no deploy key for "${CHANNEL}" — skipping registration.`)
|
|
191
|
+
process.exit(0)
|
|
192
|
+
}
|
|
151
193
|
|
|
152
194
|
const manifest = JSON.parse(readFileSync('dist/app.manifest.json', 'utf8'))
|
|
153
195
|
const appId = manifest.meta.appId
|
|
154
196
|
const version = manifest.meta.version
|
|
155
197
|
const gitHash = (() => { try { return execSync('git rev-parse --short HEAD').toString().trim() } catch { return null } })()
|
|
198
|
+
// dev: your published Lovable URL; prod: the SmartLinks CDN base. Set SMARTLINKS_BUNDLE_BASE_URL.
|
|
199
|
+
const bundleBaseUrl = process.env.SMARTLINKS_BUNDLE_BASE_URL || `https://smartlinks.app/apps/${appId}/${version}`
|
|
156
200
|
|
|
157
201
|
const res = await fetch(`${API}/api/v1/apps/${appId}/releases`, {
|
|
158
202
|
method: 'POST',
|
|
159
203
|
headers: { 'content-type': 'application/json', 'x-smartlinks-deploy-key': KEY },
|
|
160
204
|
body: JSON.stringify({
|
|
161
|
-
channel: CHANNEL,
|
|
162
|
-
|
|
163
|
-
build: { at: new Date().toISOString(), gitHash, builder: CHANNEL === 'dev' ? 'lovable' : 'cloudbuild' },
|
|
164
|
-
manifest,
|
|
165
|
-
bundleBaseUrl: `https://smartlinks.app/apps/${appId}/${version}`,
|
|
205
|
+
channel: CHANNEL, version, manifest, bundleBaseUrl,
|
|
206
|
+
build: { at: new Date().toISOString(), gitHash, builder: CHANNEL === 'dev' ? 'lovable' : 'ci' },
|
|
166
207
|
}),
|
|
167
208
|
})
|
|
168
209
|
|
|
@@ -175,7 +216,7 @@ if (!res.ok || !body.ok) {
|
|
|
175
216
|
console.log(`✅ Registered ${appId}@${version} on "${CHANNEL}" — functions: ${(body.functions || []).join(', ') || 'none'}`)
|
|
176
217
|
```
|
|
177
218
|
|
|
178
|
-
Wire it after your bundle build/hash step
|
|
219
|
+
Wire it after your bundle build/hash step:
|
|
179
220
|
|
|
180
221
|
```jsonc
|
|
181
222
|
// package.json
|
|
@@ -185,9 +226,19 @@ Wire it after your bundle build/hash step, e.g.:
|
|
|
185
226
|
}
|
|
186
227
|
```
|
|
187
228
|
|
|
188
|
-
|
|
189
|
-
`SMARTLINKS_CHANNEL=dev`.
|
|
190
|
-
- **Prod (Cloud Build)** runs the same with the **prod key** and `SMARTLINKS_CHANNEL=prod`.
|
|
229
|
+
Registration is gated by **`SMARTLINKS_CHANNEL`**, so the three Lovable build types behave correctly:
|
|
191
230
|
|
|
192
|
-
|
|
193
|
-
|
|
231
|
+
| Build | `SMARTLINKS_CHANNEL` | Result |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| **Preview / live-edit** | unset | **skips quietly** — never registers, never fails |
|
|
234
|
+
| **Dev (Publish)** | `dev` | registers to `dev` with the workspace Build-Secret key + your Lovable `SMARTLINKS_BUNDLE_BASE_URL` |
|
|
235
|
+
| **Prod (CI)** | `prod` | registers to `prod` with the prod key; a missing key **hard-fails** |
|
|
236
|
+
|
|
237
|
+
The gate is `SMARTLINKS_CHANNEL`, so **set it only where you want a release** — i.e. on the
|
|
238
|
+
Publish/CI build, not on preview. If your host exposes a publish-only signal (an env var it sets
|
|
239
|
+
only on Publish), key `SMARTLINKS_CHANNEL` off that; otherwise set it in the Publish build's env
|
|
240
|
+
and leave it unset for preview. That one variable is the difference between "this build ships a
|
|
241
|
+
release" and "this build is just a preview."
|
|
242
|
+
|
|
243
|
+
That's it: a real Publish validates + registers your app (a broken manifest or function stops
|
|
244
|
+
the deploy with an actionable error), while preview builds stay quiet.
|