snagset 0.1.16 → 0.1.19
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/astro.d.ts +1 -1
- package/dist/astro.js +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.js +7 -7
- package/dist/index.js.map +1 -1
- package/dist/next.d.ts +3 -3
- package/dist/react.d.ts +2 -2
- package/dist/vendor/types/brief.d.ts +3 -3
- package/dist/vendor/types/brief.js +2 -2
- package/dist/vendor/types/index.js +1 -1
- package/dist/vendor/types/names.d.ts +23 -22
- package/dist/vendor/types/names.js +20 -18
- package/dist/vite.d.ts +2 -2
- package/dist/vue.d.ts +1 -1
- package/dist/vue.js +1 -1
- package/package.json +1 -1
package/dist/astro.d.ts
CHANGED
package/dist/astro.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ScriptAttr } from "./vendor/types/names";
|
|
2
2
|
/**
|
|
3
|
-
* `snagset` — the npm way in
|
|
3
|
+
* `snagset` — the npm way in., and the structure with the name.
|
|
4
4
|
*
|
|
5
5
|
* ── THIS PACKAGE DOES NOT CONTAIN THE WIDGET, AND THAT IS THE DESIGN ──
|
|
6
6
|
*
|
|
@@ -17,7 +17,7 @@ import { type ScriptAttr } from "./vendor/types/names";
|
|
|
17
17
|
* screenshot code, the panels, the fuzzy anchorer and the rest arrive only if
|
|
18
18
|
* somebody actually opens the toolbar. Bundling that into `snagset` would put a
|
|
19
19
|
* quarter of a megabyte into the host application's own bundle — or force them
|
|
20
|
-
* to teach their bundler about our code-splitting — and
|
|
20
|
+
* to teach their bundler about our code-splitting — and the eager
|
|
21
21
|
* envelope, the budget the whole architecture is built around, would be a
|
|
22
22
|
* number about a file nobody loads.
|
|
23
23
|
*
|
|
@@ -26,16 +26,16 @@ import { type ScriptAttr } from "./vendor/types/names";
|
|
|
26
26
|
* · **No version skew.** The chunks are fetched from the server at the
|
|
27
27
|
* server's version. A bundled widget pinned in someone's `package.json` at
|
|
28
28
|
* an older version would request chunk names that build no longer has.
|
|
29
|
-
* · **Same-origin stays same-origin** (
|
|
29
|
+
* · **Same-origin stays same-origin** (A7). The bytes come from the
|
|
30
30
|
* instance the widget already talks to, so a client's CSP is one
|
|
31
31
|
* `script-src 'self'` entry and there is no third party to justify.
|
|
32
|
-
* · **The script tag is still sacred**
|
|
32
|
+
* · **The script tag is still sacred** — literally, not by
|
|
33
33
|
* analogy. This package emits exactly the tag the docs tell you to paste,
|
|
34
34
|
* so a bug here cannot produce behaviour the tag cannot.
|
|
35
35
|
*
|
|
36
36
|
* ── AND NO CUSTOM ELEMENT ──
|
|
37
37
|
*
|
|
38
|
-
*
|
|
38
|
+
* Sketched registering one so that "Vue, Svelte and Astro need no adapter
|
|
39
39
|
* at all". That was reasoning about a *bundled* widget, where a framework needs
|
|
40
40
|
* something to render. With a shim there is nothing to render — `init()` is
|
|
41
41
|
* already framework-agnostic, and the framework subpaths are lifecycle glue
|
|
@@ -83,7 +83,7 @@ export declare function tagFor(options: InitOptions): {
|
|
|
83
83
|
* ── WHY `init` AND NOT `mount` ──
|
|
84
84
|
*
|
|
85
85
|
* Because the product already had a name for this and it was not mine to
|
|
86
|
-
* choose.
|
|
86
|
+
* choose. defines
|
|
87
87
|
* **`Snagset.init(config)`** as the public JS API — *"may be called repeatedly
|
|
88
88
|
* before activation; each call merges"* — and `window.Snagset.init` /
|
|
89
89
|
* `window.Snagset.destroy` are on the live object right now.
|
|
@@ -92,14 +92,14 @@ export declare function tagFor(options: InitOptions): {
|
|
|
92
92
|
* vocabulary imported into a package whose underlying object has said `init`
|
|
93
93
|
* since 02 draft 1. A developer reading `snagset.mount()` in their app and
|
|
94
94
|
* `Snagset.init()` in the console would reasonably conclude they were two
|
|
95
|
-
* different things. Raised by
|
|
95
|
+
* different things. Raised by the maintainer — *"init seems better than mount"* — and
|
|
96
96
|
* he is right for a better reason than either of us gave at the time.
|
|
97
97
|
*
|
|
98
98
|
* ── REPEATED CALLS MERGE, LIKE THE SPEC SAYS ──
|
|
99
99
|
*
|
|
100
100
|
* A second `init()` does not add a second tag (that would boot a second
|
|
101
101
|
* widget). It forwards the new config to `Snagset.init()`, which deep-merges
|
|
102
|
-
* it — so this behaves the way
|
|
102
|
+
* it — so this behaves the way documents rather than being a same-named
|
|
103
103
|
* function with different rules. When the widget has not finished loading the
|
|
104
104
|
* config is QUEUED and flushed on the script's `load` event, because a caller
|
|
105
105
|
* has no way to know whether an async script has arrived yet and "your second
|
|
@@ -109,7 +109,7 @@ export declare function tagFor(options: InitOptions): {
|
|
|
109
109
|
*/
|
|
110
110
|
declare function init(options: InitOptions): () => void;
|
|
111
111
|
/**
|
|
112
|
-
* Take Snagset off the page —
|
|
112
|
+
* Take Snagset off the page — 's
|
|
113
113
|
* `Snagset.destroy()`.
|
|
114
114
|
*
|
|
115
115
|
* Delegates to the widget's OWN teardown rather than removing the script
|
|
@@ -122,13 +122,13 @@ declare function destroy(): void;
|
|
|
122
122
|
/**
|
|
123
123
|
* Is the tag on this page?
|
|
124
124
|
*
|
|
125
|
-
* `isInstalled`, not `isActive`:
|
|
125
|
+
* `isInstalled`, not `isActive`: The `state` is `inert | dormant | active`
|
|
126
126
|
* and "active" already means *the toolbar is open*, which is a different
|
|
127
127
|
* question with a different answer. Read `window.Snagset.state` for that one.
|
|
128
128
|
*/
|
|
129
129
|
declare function isInstalled(): boolean;
|
|
130
130
|
/**
|
|
131
|
-
* The default export — the package's own name, carrying
|
|
131
|
+
* The default export — the package's own name, carrying the verbs.
|
|
132
132
|
*
|
|
133
133
|
* An OBJECT with `init`, not a callable. The first version made `snagset({…})`
|
|
134
134
|
* itself the call, on the argument that one verb should be the noun; with the
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export function tagFor(options) {
|
|
|
10
10
|
// `false` is dropped rather than written as the string "false". Every one
|
|
11
11
|
// of these attributes is read by `loader.ts` as a STRING, and the presence
|
|
12
12
|
// of `data-snag-disabled="false"` reads as "disabled" to anything doing a
|
|
13
|
-
// has-attribute check — which is the shape of kill switch
|
|
13
|
+
// has-attribute check — which is the shape of kill switch uses.
|
|
14
14
|
if (value === false)
|
|
15
15
|
continue;
|
|
16
16
|
attrs[scriptAttr(key)] = value === true ? "" : String(value);
|
|
@@ -33,7 +33,7 @@ export function tagFor(options) {
|
|
|
33
33
|
* ── WHY `init` AND NOT `mount` ──
|
|
34
34
|
*
|
|
35
35
|
* Because the product already had a name for this and it was not mine to
|
|
36
|
-
* choose.
|
|
36
|
+
* choose. defines
|
|
37
37
|
* **`Snagset.init(config)`** as the public JS API — *"may be called repeatedly
|
|
38
38
|
* before activation; each call merges"* — and `window.Snagset.init` /
|
|
39
39
|
* `window.Snagset.destroy` are on the live object right now.
|
|
@@ -42,14 +42,14 @@ export function tagFor(options) {
|
|
|
42
42
|
* vocabulary imported into a package whose underlying object has said `init`
|
|
43
43
|
* since 02 draft 1. A developer reading `snagset.mount()` in their app and
|
|
44
44
|
* `Snagset.init()` in the console would reasonably conclude they were two
|
|
45
|
-
* different things. Raised by
|
|
45
|
+
* different things. Raised by the maintainer — *"init seems better than mount"* — and
|
|
46
46
|
* he is right for a better reason than either of us gave at the time.
|
|
47
47
|
*
|
|
48
48
|
* ── REPEATED CALLS MERGE, LIKE THE SPEC SAYS ──
|
|
49
49
|
*
|
|
50
50
|
* A second `init()` does not add a second tag (that would boot a second
|
|
51
51
|
* widget). It forwards the new config to `Snagset.init()`, which deep-merges
|
|
52
|
-
* it — so this behaves the way
|
|
52
|
+
* it — so this behaves the way documents rather than being a same-named
|
|
53
53
|
* function with different rules. When the widget has not finished loading the
|
|
54
54
|
* config is QUEUED and flushed on the script's `load` event, because a caller
|
|
55
55
|
* has no way to know whether an async script has arrived yet and "your second
|
|
@@ -109,7 +109,7 @@ function flush() {
|
|
|
109
109
|
merge(options);
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
|
-
* Take Snagset off the page —
|
|
112
|
+
* Take Snagset off the page — 's
|
|
113
113
|
* `Snagset.destroy()`.
|
|
114
114
|
*
|
|
115
115
|
* Delegates to the widget's OWN teardown rather than removing the script
|
|
@@ -128,7 +128,7 @@ function destroy() {
|
|
|
128
128
|
/**
|
|
129
129
|
* Is the tag on this page?
|
|
130
130
|
*
|
|
131
|
-
* `isInstalled`, not `isActive`:
|
|
131
|
+
* `isInstalled`, not `isActive`: The `state` is `inert | dormant | active`
|
|
132
132
|
* and "active" already means *the toolbar is open*, which is a different
|
|
133
133
|
* question with a different answer. Read `window.Snagset.state` for that one.
|
|
134
134
|
*/
|
|
@@ -136,7 +136,7 @@ function isInstalled() {
|
|
|
136
136
|
return typeof window !== "undefined" && !!window[INSTALLED];
|
|
137
137
|
}
|
|
138
138
|
/**
|
|
139
|
-
* The default export — the package's own name, carrying
|
|
139
|
+
* The default export — the package's own name, carrying the verbs.
|
|
140
140
|
*
|
|
141
141
|
* An OBJECT with `init`, not a callable. The first version made `snagset({…})`
|
|
142
142
|
* itself the call, on the argument that one verb should be the noun; with the
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAmB,MAAM,sBAAsB,CAAC;AAwE5E,MAAM,SAAS,GAAG,2BAA2B,CAAC;AAE9C,6EAA6E;AAC7E,MAAM,UAAU,MAAM,CAAC,OAAoB;IACzC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtD,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,MAAM,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC1F,0EAA0E;QAC1E,2EAA2E;QAC3E,0EAA0E;QAC1E,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/next.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createElement } from "react";
|
|
2
2
|
import { type InitOptions } from "./index.ts";
|
|
3
3
|
/**
|
|
4
|
-
* `snagset/next
|
|
4
|
+
* `snagset/next`.
|
|
5
5
|
*
|
|
6
6
|
* ```tsx
|
|
7
7
|
* // app/layout.tsx
|
|
@@ -28,7 +28,7 @@ import { type InitOptions } from "./index.ts";
|
|
|
28
28
|
* Vercel's own toolbar ships one because their setup needs `next.config`
|
|
29
29
|
* rewrites to proxy toolbar traffic through the deployment. Ours needs no
|
|
30
30
|
* proxy: the widget is served by the studio's instance and talks back to that
|
|
31
|
-
* same origin
|
|
31
|
+
* same origin. A config wrapper would exist to look like theirs, not to
|
|
32
32
|
* do anything — the component is the whole install.
|
|
33
33
|
*
|
|
34
34
|
* ── PROPS, OR `NEXT_PUBLIC_SNAGSET_*` ──
|
|
@@ -37,7 +37,7 @@ import { type InitOptions } from "./index.ts";
|
|
|
37
37
|
* `NEXT_PUBLIC_SNAGSET_SITE`, so per-environment values live where a Next
|
|
38
38
|
* project already keeps them (`.env.local`, the host's env UI) instead of in
|
|
39
39
|
* the layout. The names carry Next's own public prefix — deliberately NOT bare
|
|
40
|
-
* `SNAGSET_*`, which is the server's reserved namespace
|
|
40
|
+
* `SNAGSET_*`, which is the server's reserved namespace: an instance
|
|
41
41
|
* colocated with the app must never find widget config in variables it treats
|
|
42
42
|
* as its own and refuses to boot on.
|
|
43
43
|
*
|
package/dist/react.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type InitOptions } from "./index.ts";
|
|
2
2
|
/**
|
|
3
|
-
* `snagset/react
|
|
3
|
+
* `snagset/react`, and the twenty-line wrapper predicted.
|
|
4
4
|
*
|
|
5
5
|
* ```tsx
|
|
6
6
|
* import { Snagset } from "snagset/react";
|
|
@@ -9,7 +9,7 @@ import { type InitOptions } from "./index.ts";
|
|
|
9
9
|
* ```
|
|
10
10
|
*
|
|
11
11
|
* It renders NOTHING. There is no element to place, no wrapper div, no portal
|
|
12
|
-
*
|
|
12
|
+
* the widget owns its own root in the DOM (the shadow host) and this
|
|
13
13
|
* component's whole job is to run `init()` while it is on screen. Returning
|
|
14
14
|
* `null` is the honest expression of that, and it means the component can sit
|
|
15
15
|
* anywhere in a tree without affecting layout.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* A thread as a BRIEF — the markdown an agent, a ticket or a clipboard wants:
|
|
3
3
|
* Where to look · What's wrong · Environment · Breadcrumbs · Screenshot.
|
|
4
4
|
*
|
|
5
|
-
* ONE formatter in the shared package
|
|
5
|
+
* ONE formatter in the shared package, so the dashboard's
|
|
6
6
|
* Copy button, the MCP server's `get_thread` and the server's own markdown
|
|
7
7
|
* route cannot drift from one another. Pure: a thread in, a string out, no
|
|
8
8
|
* clock, so the same thread always produces the same brief.
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
* before it is written. The dashboard passes nothing (the clipboard is the
|
|
17
17
|
* studio's own), the MCP server passes `@snagset/adapters`' fence so a model
|
|
18
18
|
* reads `<untrusted-content kind="body">…</untrusted-content>` around the
|
|
19
|
-
* client's words
|
|
19
|
+
* client's words. Ids, keys, timestamps and enums we
|
|
20
20
|
* minted are written bare.
|
|
21
21
|
*/
|
|
22
22
|
export type BriefFenceKind = "body" | "name" | "label" | "selector" | "breadcrumb";
|
|
23
23
|
export interface BriefComment {
|
|
24
|
-
/** Null is a tombstone
|
|
24
|
+
/** Null is a tombstone and is left out. */
|
|
25
25
|
body: string | null;
|
|
26
26
|
createdAt: string;
|
|
27
27
|
author?: {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* A thread as a BRIEF — the markdown an agent, a ticket or a clipboard wants:
|
|
3
3
|
* Where to look · What's wrong · Environment · Breadcrumbs · Screenshot.
|
|
4
4
|
*
|
|
5
|
-
* ONE formatter in the shared package
|
|
5
|
+
* ONE formatter in the shared package, so the dashboard's
|
|
6
6
|
* Copy button, the MCP server's `get_thread` and the server's own markdown
|
|
7
7
|
* route cannot drift from one another. Pure: a thread in, a string out, no
|
|
8
8
|
* clock, so the same thread always produces the same brief.
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* before it is written. The dashboard passes nothing (the clipboard is the
|
|
17
17
|
* studio's own), the MCP server passes `@snagset/adapters`' fence so a model
|
|
18
18
|
* reads `<untrusted-content kind="body">…</untrusted-content>` around the
|
|
19
|
-
* client's words
|
|
19
|
+
* client's words. Ids, keys, timestamps and enums we
|
|
20
20
|
* minted are written bare.
|
|
21
21
|
*/
|
|
22
22
|
import { param } from "./names.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @snagset/types — shared types and the executable Name Registry.
|
|
2
2
|
// The names module is generated from registry.json (see scripts/gen-names.mjs);
|
|
3
|
-
// domain types
|
|
3
|
+
// domain types land here as the packages that own them are built.
|
|
4
4
|
export * from "./names.js";
|
|
@@ -33,7 +33,7 @@ export declare const env: (name: string) => string;
|
|
|
33
33
|
export declare const pgType: (name: string) => string;
|
|
34
34
|
/** @returns e.g. `snagset_http_requests_total` */
|
|
35
35
|
export declare const metric: (name: string) => string;
|
|
36
|
-
/** window.* names
|
|
36
|
+
/** window.* names. Dunders are internal/test affordances, not public API. */
|
|
37
37
|
export declare const GLOBALS: {
|
|
38
38
|
readonly api: "Snagset";
|
|
39
39
|
readonly config: "SnagsetConfig";
|
|
@@ -41,19 +41,19 @@ export declare const GLOBALS: {
|
|
|
41
41
|
readonly assetBase: "__SNAGSET_ASSET_BASE__";
|
|
42
42
|
readonly collisionFallback: "__snagset__";
|
|
43
43
|
};
|
|
44
|
-
/** data-*-attributes on the host <script> tag
|
|
44
|
+
/** data-*-attributes on the host <script> tag. */
|
|
45
45
|
export type ScriptAttr = "site" | "host" | "disabled" | "env" | "mode" | "badge" | "lang" | "theme" | "position" | "offset" | "assetBase" | "branch" | "build" | "storage" | "hotkey" | "allowAutomation" | "screenshots" | "maskSelectors" | "nonce" | "autoMount";
|
|
46
46
|
export declare const scriptAttr: (name: ScriptAttr) => string;
|
|
47
|
-
/** DOM the widget authors on itself
|
|
47
|
+
/** DOM the widget authors on itself. */
|
|
48
48
|
export type WidgetAttr = "root";
|
|
49
49
|
export declare const widgetAttr: (name: WidgetAttr) => string;
|
|
50
|
-
/** Attributes the host application may author
|
|
50
|
+
/** Attributes the host application may author. */
|
|
51
51
|
export type HostAttr = "anchor" | "ignore" | "mask" | "nomask" | "src" | "component";
|
|
52
52
|
export declare const hostAttr: (name: HostAttr) => string;
|
|
53
|
-
/** Class-form masking hooks
|
|
53
|
+
/** Class-form masking hooks. */
|
|
54
54
|
export type CssClass = "mask" | "block";
|
|
55
55
|
export declare const cssClass: (name: CssClass) => string;
|
|
56
|
-
/** Custom properties (
|
|
56
|
+
/** Custom properties (the prefix, enumerated). The design makes every one of these public SemVer surface, so they are registered rather than minted at the point of use. Values are NOT here — the registry governs names, never design. */
|
|
57
57
|
export declare const CSS_VAR: {
|
|
58
58
|
readonly font: "--snag-font";
|
|
59
59
|
readonly accent: "--snag-accent";
|
|
@@ -97,7 +97,7 @@ export declare const cssVar: (name: CssVar) => string;
|
|
|
97
97
|
export declare const cssRef: (name: CssVar) => string;
|
|
98
98
|
export type QueryParam = "t" | "off" | "debug" | "theme";
|
|
99
99
|
export type FragmentParam = "k";
|
|
100
|
-
/** @returns e.g. `snag_t`. The review-link secret is a FRAGMENT param
|
|
100
|
+
/** @returns e.g. `snag_t`. The review-link secret is a FRAGMENT param. */
|
|
101
101
|
export declare const param: (name: QueryParam | FragmentParam) => string;
|
|
102
102
|
export declare const RESERVED_URL_PARAMS: {
|
|
103
103
|
readonly query: readonly ["snag_t", "snag_off", "snag_debug", "snag_theme"];
|
|
@@ -105,13 +105,14 @@ export declare const RESERVED_URL_PARAMS: {
|
|
|
105
105
|
};
|
|
106
106
|
/** Point consts for hot paths: a chunk needing ONE key imports it and
|
|
107
107
|
* drops the whole table — object properties cannot tree-shake, and the
|
|
108
|
-
* panels chunk was carrying ten keys to read two
|
|
108
|
+
* panels chunk was carrying ten keys to read two. */
|
|
109
109
|
export declare const DISCLOSURE_KEY = "snag:disclosure:v1";
|
|
110
110
|
export declare const IDENTITY_KEY = "snag:identity";
|
|
111
111
|
export declare const THEME_ATTR = "data-snag-theme";
|
|
112
|
-
/** Web-storage keys
|
|
112
|
+
/** Web-storage keys. Parameterised keys are functions. */
|
|
113
113
|
export declare const storageKey: {
|
|
114
114
|
readonly session: (uid: string) => string;
|
|
115
|
+
readonly silent: (uid: string) => string;
|
|
115
116
|
readonly identity: "snag:identity";
|
|
116
117
|
readonly threads: (uid: string, env: string) => string;
|
|
117
118
|
readonly seen: (uid: string, env: string) => string;
|
|
@@ -123,28 +124,28 @@ export declare const storageKey: {
|
|
|
123
124
|
readonly seenCoach: "snag:seen-coach";
|
|
124
125
|
readonly disclosure: "snag:disclosure:v1";
|
|
125
126
|
};
|
|
126
|
-
/** The v0.1 IndexedDB blob store
|
|
127
|
+
/** The v0.1 IndexedDB blob store — one database, one
|
|
127
128
|
* object store, shared by screenshots, reviewer images and the v2 outbox. */
|
|
128
129
|
export declare const IDB: {
|
|
129
130
|
readonly database: "snag:blobs";
|
|
130
131
|
readonly store: "blobs";
|
|
131
132
|
};
|
|
132
|
-
/** Anchored regex sources matching every registered key —
|
|
133
|
-
export declare const STORAGE_KEY_PATTERNS: readonly ["^snag:session:.+$", "^snag:identity$", "^snag:threads:.+:.+$", "^snag:seen:.+:.+$", "^snag:counts:.+$", "^snag:draft:.+:.+$", "^snag:outbox:.+$", "^snag:mode$", "^snag:handoff$", "^snag:seen-coach$", "^snag:disclosure:v1$"];
|
|
134
|
-
/** The WIDGET's two
|
|
133
|
+
/** Anchored regex sources matching every registered key — the storage diff. */
|
|
134
|
+
export declare const STORAGE_KEY_PATTERNS: readonly ["^snag:session:.+$", "^snag:silent:.+$", "^snag:identity$", "^snag:threads:.+:.+$", "^snag:seen:.+:.+$", "^snag:counts:.+$", "^snag:draft:.+:.+$", "^snag:outbox:.+$", "^snag:mode$", "^snag:handoff$", "^snag:seen-coach$", "^snag:disclosure:v1$"];
|
|
135
|
+
/** The WIDGET's two. Neither carries a credential, and no cookie authenticates the widget API — it runs on somebody else's origin. */
|
|
135
136
|
export declare const COOKIE: {
|
|
136
137
|
readonly off: "snag_off";
|
|
137
138
|
readonly on: "snag_on";
|
|
138
139
|
};
|
|
139
|
-
/** The dashboard's session + CSRF pair
|
|
140
|
+
/** The dashboard's session + CSRF pair — first-party, on the server's own origin, owner audience. */
|
|
140
141
|
export declare const DASHBOARD_COOKIE: {
|
|
141
142
|
readonly session: "snag_session";
|
|
142
143
|
readonly csrf: "snag_csrf";
|
|
143
144
|
};
|
|
144
|
-
/**
|
|
145
|
+
/** The design names these two constants directly; both spellings resolve to the same string. */
|
|
145
146
|
export declare const DASHBOARD_SESSION_COOKIE: "snag_session";
|
|
146
147
|
export declare const DASHBOARD_CSRF_COOKIE: "snag_csrf";
|
|
147
|
-
/** Built widget chunks
|
|
148
|
+
/** Built widget chunks. Preact lives only in `panels`. */
|
|
148
149
|
export declare const ARTIFACT: {
|
|
149
150
|
readonly stub: "snag.js";
|
|
150
151
|
readonly runtime: "snag.runtime.js";
|
|
@@ -157,7 +158,7 @@ export declare const ARTIFACT: {
|
|
|
157
158
|
readonly dock: "snag.dock.js";
|
|
158
159
|
readonly text: "snag.text.js";
|
|
159
160
|
};
|
|
160
|
-
/** Wire-form entity id prefixes
|
|
161
|
+
/** Wire-form entity id prefixes. Not brand-derived. */
|
|
161
162
|
export declare const ID_PREFIX: {
|
|
162
163
|
readonly project: "prj_";
|
|
163
164
|
readonly thread: "thr_";
|
|
@@ -167,11 +168,11 @@ export declare const ID_PREFIX: {
|
|
|
167
168
|
readonly link: "lnk_";
|
|
168
169
|
readonly round: "rnd_";
|
|
169
170
|
};
|
|
170
|
-
/** Credential literals
|
|
171
|
+
/** Credential literals. Brand-DERIVED, and deliberately not the three-letter row shape: the literal is what gets registered with secret scanning, so a token pasted into a public repo is reported. */
|
|
171
172
|
export declare const CREDENTIAL_PREFIX: {
|
|
172
173
|
readonly mcp: "snagmcp_";
|
|
173
174
|
};
|
|
174
|
-
/** CustomEvents dispatched on document
|
|
175
|
+
/** CustomEvents dispatched on document. */
|
|
175
176
|
export declare const DOM_EVENT: {
|
|
176
177
|
readonly ready: "snagset:ready";
|
|
177
178
|
readonly activate: "snagset:activate";
|
|
@@ -179,7 +180,7 @@ export declare const DOM_EVENT: {
|
|
|
179
180
|
readonly threadCreated: "snagset:thread-created";
|
|
180
181
|
readonly threadResolved: "snagset:thread-resolved";
|
|
181
182
|
};
|
|
182
|
-
/** Request/response header names inside
|
|
183
|
+
/** Request/response header names inside the prefix. */
|
|
183
184
|
export declare const HTTP_HEADER: {
|
|
184
185
|
readonly client: "x-snagset-client";
|
|
185
186
|
readonly schema: "x-snagset-schema";
|
|
@@ -197,11 +198,11 @@ export declare const HTTP_HEADER: {
|
|
|
197
198
|
readonly requestId: "x-snagset-request-id";
|
|
198
199
|
readonly mcpTransport: "x-snagset-mcp-transport";
|
|
199
200
|
};
|
|
200
|
-
/** Host-authored `<meta name>` keys we READ and never mint
|
|
201
|
+
/** Host-authored `<meta name>` keys we READ and never mint .: `route` is the only one. */
|
|
201
202
|
export declare const META_NAME: {
|
|
202
203
|
readonly route: "snagset:route";
|
|
203
204
|
};
|
|
204
|
-
/** Keys for Symbol.for() patch bookkeeping
|
|
205
|
+
/** Keys for Symbol.for() patch bookkeeping. */
|
|
205
206
|
export declare const SYMBOL_KEY: {
|
|
206
207
|
readonly original: "snagset.original";
|
|
207
208
|
readonly wrapped: "snagset.wrapped";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Source of truth: packages/types/registry.json
|
|
4
4
|
// Regenerate: pnpm gen:names (CI runs `pnpm gen:names:check`)
|
|
5
5
|
//
|
|
6
|
-
// The Name Registry
|
|
6
|
+
// The Name Registry made executable. Every token
|
|
7
7
|
// below is DERIVED from registry.json's `brand` block — the product name lives
|
|
8
8
|
// in exactly one place. test/rename.test.ts proves it: flip the brand, and no
|
|
9
9
|
// token of the old one survives. SCHEMA_VERSION is the one deliberate literal.
|
|
@@ -43,7 +43,7 @@ export const env = (name) => ENV_PREFIX + name;
|
|
|
43
43
|
export const pgType = (name) => PG_TYPE_PREFIX + name;
|
|
44
44
|
/** @returns e.g. `snagset_http_requests_total` */
|
|
45
45
|
export const metric = (name) => METRIC_PREFIX + name;
|
|
46
|
-
/** window.* names
|
|
46
|
+
/** window.* names. Dunders are internal/test affordances, not public API. */
|
|
47
47
|
export const GLOBALS = {
|
|
48
48
|
api: "Snagset",
|
|
49
49
|
config: "SnagsetConfig",
|
|
@@ -92,7 +92,7 @@ const cssClassToken = {
|
|
|
92
92
|
block: "snag-block",
|
|
93
93
|
};
|
|
94
94
|
export const cssClass = (name) => cssClassToken[name];
|
|
95
|
-
/** Custom properties (
|
|
95
|
+
/** Custom properties (the prefix, enumerated). The design makes every one of these public SemVer surface, so they are registered rather than minted at the point of use. Values are NOT here — the registry governs names, never design. */
|
|
96
96
|
export const CSS_VAR = {
|
|
97
97
|
font: "--snag-font",
|
|
98
98
|
accent: "--snag-accent",
|
|
@@ -133,7 +133,7 @@ export const CSS_VAR_GROUPS = {
|
|
|
133
133
|
export const cssVar = (name) => CSS_VAR[name];
|
|
134
134
|
/** @returns e.g. `var(--snag-bg)` — what stylesheets actually interpolate. */
|
|
135
135
|
export const cssRef = (name) => `var(${CSS_VAR[name]})`;
|
|
136
|
-
/** @returns e.g. `snag_t`. The review-link secret is a FRAGMENT param
|
|
136
|
+
/** @returns e.g. `snag_t`. The review-link secret is a FRAGMENT param. */
|
|
137
137
|
export const param = (name) => "snag_" + name;
|
|
138
138
|
export const RESERVED_URL_PARAMS = {
|
|
139
139
|
query: ["snag_t", "snag_off", "snag_debug", "snag_theme"],
|
|
@@ -141,13 +141,14 @@ export const RESERVED_URL_PARAMS = {
|
|
|
141
141
|
};
|
|
142
142
|
/** Point consts for hot paths: a chunk needing ONE key imports it and
|
|
143
143
|
* drops the whole table — object properties cannot tree-shake, and the
|
|
144
|
-
* panels chunk was carrying ten keys to read two
|
|
144
|
+
* panels chunk was carrying ten keys to read two. */
|
|
145
145
|
export const DISCLOSURE_KEY = "snag:disclosure:v1";
|
|
146
146
|
export const IDENTITY_KEY = "snag:identity";
|
|
147
147
|
export const THEME_ATTR = "data-snag-theme";
|
|
148
|
-
/** Web-storage keys
|
|
148
|
+
/** Web-storage keys. Parameterised keys are functions. */
|
|
149
149
|
export const storageKey = {
|
|
150
150
|
session: (uid) => `snag:session:${uid}`,
|
|
151
|
+
silent: (uid) => `snag:silent:${uid}`,
|
|
151
152
|
identity: IDENTITY_KEY,
|
|
152
153
|
threads: (uid, env) => `snag:threads:${uid}:${env}`,
|
|
153
154
|
seen: (uid, env) => `snag:seen:${uid}:${env}`,
|
|
@@ -159,15 +160,16 @@ export const storageKey = {
|
|
|
159
160
|
seenCoach: "snag:seen-coach",
|
|
160
161
|
disclosure: DISCLOSURE_KEY,
|
|
161
162
|
};
|
|
162
|
-
/** The v0.1 IndexedDB blob store
|
|
163
|
+
/** The v0.1 IndexedDB blob store — one database, one
|
|
163
164
|
* object store, shared by screenshots, reviewer images and the v2 outbox. */
|
|
164
165
|
export const IDB = {
|
|
165
166
|
database: "snag:blobs",
|
|
166
167
|
store: "blobs",
|
|
167
168
|
};
|
|
168
|
-
/** Anchored regex sources matching every registered key —
|
|
169
|
+
/** Anchored regex sources matching every registered key — the storage diff. */
|
|
169
170
|
export const STORAGE_KEY_PATTERNS = [
|
|
170
171
|
"^snag:session:.+$",
|
|
172
|
+
"^snag:silent:.+$",
|
|
171
173
|
"^snag:identity$",
|
|
172
174
|
"^snag:threads:.+:.+$",
|
|
173
175
|
"^snag:seen:.+:.+$",
|
|
@@ -179,20 +181,20 @@ export const STORAGE_KEY_PATTERNS = [
|
|
|
179
181
|
"^snag:seen-coach$",
|
|
180
182
|
"^snag:disclosure:v1$",
|
|
181
183
|
];
|
|
182
|
-
/** The WIDGET's two
|
|
184
|
+
/** The WIDGET's two. Neither carries a credential, and no cookie authenticates the widget API — it runs on somebody else's origin. */
|
|
183
185
|
export const COOKIE = {
|
|
184
186
|
off: "snag_off",
|
|
185
187
|
on: "snag_on",
|
|
186
188
|
};
|
|
187
|
-
/** The dashboard's session + CSRF pair
|
|
189
|
+
/** The dashboard's session + CSRF pair — first-party, on the server's own origin, owner audience. */
|
|
188
190
|
export const DASHBOARD_COOKIE = {
|
|
189
191
|
session: "snag_session",
|
|
190
192
|
csrf: "snag_csrf",
|
|
191
193
|
};
|
|
192
|
-
/**
|
|
194
|
+
/** The design names these two constants directly; both spellings resolve to the same string. */
|
|
193
195
|
export const DASHBOARD_SESSION_COOKIE = DASHBOARD_COOKIE.session;
|
|
194
196
|
export const DASHBOARD_CSRF_COOKIE = DASHBOARD_COOKIE.csrf;
|
|
195
|
-
/** Built widget chunks
|
|
197
|
+
/** Built widget chunks. Preact lives only in `panels`. */
|
|
196
198
|
export const ARTIFACT = {
|
|
197
199
|
stub: "snag.js",
|
|
198
200
|
runtime: "snag.runtime.js",
|
|
@@ -205,7 +207,7 @@ export const ARTIFACT = {
|
|
|
205
207
|
dock: "snag.dock.js",
|
|
206
208
|
text: "snag.text.js",
|
|
207
209
|
};
|
|
208
|
-
/** Wire-form entity id prefixes
|
|
210
|
+
/** Wire-form entity id prefixes. Not brand-derived. */
|
|
209
211
|
export const ID_PREFIX = {
|
|
210
212
|
project: "prj_",
|
|
211
213
|
thread: "thr_",
|
|
@@ -215,11 +217,11 @@ export const ID_PREFIX = {
|
|
|
215
217
|
link: "lnk_",
|
|
216
218
|
round: "rnd_",
|
|
217
219
|
};
|
|
218
|
-
/** Credential literals
|
|
220
|
+
/** Credential literals. Brand-DERIVED, and deliberately not the three-letter row shape: the literal is what gets registered with secret scanning, so a token pasted into a public repo is reported. */
|
|
219
221
|
export const CREDENTIAL_PREFIX = {
|
|
220
222
|
mcp: "snagmcp_",
|
|
221
223
|
};
|
|
222
|
-
/** CustomEvents dispatched on document
|
|
224
|
+
/** CustomEvents dispatched on document. */
|
|
223
225
|
export const DOM_EVENT = {
|
|
224
226
|
ready: "snagset:ready",
|
|
225
227
|
activate: "snagset:activate",
|
|
@@ -227,7 +229,7 @@ export const DOM_EVENT = {
|
|
|
227
229
|
threadCreated: "snagset:thread-created",
|
|
228
230
|
threadResolved: "snagset:thread-resolved",
|
|
229
231
|
};
|
|
230
|
-
/** Request/response header names inside
|
|
232
|
+
/** Request/response header names inside the prefix. */
|
|
231
233
|
export const HTTP_HEADER = {
|
|
232
234
|
client: "x-snagset-client",
|
|
233
235
|
schema: "x-snagset-schema",
|
|
@@ -245,11 +247,11 @@ export const HTTP_HEADER = {
|
|
|
245
247
|
requestId: "x-snagset-request-id",
|
|
246
248
|
mcpTransport: "x-snagset-mcp-transport",
|
|
247
249
|
};
|
|
248
|
-
/** Host-authored `<meta name>` keys we READ and never mint
|
|
250
|
+
/** Host-authored `<meta name>` keys we READ and never mint .: `route` is the only one. */
|
|
249
251
|
export const META_NAME = {
|
|
250
252
|
route: "snagset:route",
|
|
251
253
|
};
|
|
252
|
-
/** Keys for Symbol.for() patch bookkeeping
|
|
254
|
+
/** Keys for Symbol.for() patch bookkeeping. */
|
|
253
255
|
export const SYMBOL_KEY = {
|
|
254
256
|
original: "snagset.original",
|
|
255
257
|
wrapped: "snagset.wrapped",
|
package/dist/vite.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type InitOptions } from "./index.ts";
|
|
2
2
|
/**
|
|
3
|
-
* `snagset/vite
|
|
3
|
+
* `snagset/vite`, the config-level install.
|
|
4
4
|
*
|
|
5
5
|
* ```ts
|
|
6
6
|
* // vite.config.ts
|
|
@@ -30,7 +30,7 @@ import { type InitOptions } from "./index.ts";
|
|
|
30
30
|
* ── DEV AND BUILD BOTH, DELIBERATELY ──
|
|
31
31
|
*
|
|
32
32
|
* The tag is safe in a production build because who sees the toolbar is a
|
|
33
|
-
* DASHBOARD setting, checked by the stub on load
|
|
33
|
+
* DASHBOARD setting, checked by the stub on load — shipping the tag is
|
|
34
34
|
* not showing the toolbar. So the plugin does not carry an `enabled`/`dev`
|
|
35
35
|
* option that re-answers a question Vite already answers natively: a project
|
|
36
36
|
* that wants the tag only in dev writes the standard idiom
|
package/dist/vue.d.ts
CHANGED
package/dist/vue.js
CHANGED