@xtrable-ltd/nanoesis 0.1.2 → 0.1.5

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 (26) hide show
  1. package/dist/adapter-azure-blob.js +1 -1
  2. package/dist/{chunk-22WHPW5E.js → chunk-S23S4ZAK.js} +25 -2
  3. package/dist/editor-api.d.ts +25 -9
  4. package/dist/editor-api.js +32 -45
  5. package/dist/index.d.ts +21 -1
  6. package/dist/index.js +1 -1
  7. package/editor/assets/{TemplatesPane-zK8lIC02.js → TemplatesPane-CEKbBX1Y.js} +172 -172
  8. package/editor/assets/{cssMode-Dx60SobP.js → cssMode-q1Nw_pOI.js} +1 -1
  9. package/editor/assets/{freemarker2-DGQjpiaU.js → freemarker2-D4uWo9kP.js} +1 -1
  10. package/editor/assets/{handlebars-BltQV8dV.js → handlebars-DIXKS_PM.js} +1 -1
  11. package/editor/assets/{html-Dcoxpshq.js → html-WMfbPtFq.js} +1 -1
  12. package/editor/assets/{htmlMode-CVqSJo7C.js → htmlMode-D1MWdaop.js} +1 -1
  13. package/editor/assets/{index-Dj_8wB_d.css → index-BRPY7tEn.css} +1 -1
  14. package/editor/assets/{index-BSlglIW6.js → index-erqFXslE.js} +69 -71
  15. package/editor/assets/{javascript-Bl74P5-A.js → javascript-C0daj-se.js} +1 -1
  16. package/editor/assets/{jsonMode-CTxdbzE_.js → jsonMode-F4j8hmn2.js} +1 -1
  17. package/editor/assets/{liquid-TXEIIcAb.js → liquid-BmXUpyt6.js} +1 -1
  18. package/editor/assets/{mdx-C7X2Fz3X.js → mdx-wzY123NO.js} +1 -1
  19. package/editor/assets/{python-BIiW5QXV.js → python-WOKQ0Svl.js} +1 -1
  20. package/editor/assets/{razor-CUdWEQ3M.js → razor-B9Yg1Ydt.js} +1 -1
  21. package/editor/assets/{tsMode-D_2_BwYS.js → tsMode-966q_lbW.js} +1 -1
  22. package/editor/assets/{typescript-BdSyn6PC.js → typescript-dxbYO44F.js} +1 -1
  23. package/editor/assets/{xml-JVU5PVkk.js → xml-BHa7-pyl.js} +1 -1
  24. package/editor/assets/{yaml-D2YDV-us.js → yaml-CcgAVYu7.js} +1 -1
  25. package/editor/index.html +2 -2
  26. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  contentTypeFor
3
- } from "./chunk-22WHPW5E.js";
3
+ } from "./chunk-S23S4ZAK.js";
4
4
 
5
5
  // ../../adapters/azure-blob/src/container.ts
6
6
  var InMemoryBlobContainer = class {
@@ -2430,8 +2430,9 @@ var noopPurgeService = {
2430
2430
  var DEFAULT_WRITE_CONCURRENCY = 8;
2431
2431
  async function publishSite(source, sink, options = {}) {
2432
2432
  const validation = await validateSite(source);
2433
+ const summary = summarizeTree(await loadContentTree(source));
2433
2434
  if (!validation.ok) {
2434
- return { ok: false, validation, written: [] };
2435
+ return { ok: false, validation, written: [], summary };
2435
2436
  }
2436
2437
  const {
2437
2438
  purge = noopPurgeService,
@@ -2454,7 +2455,29 @@ async function publishSite(source, sink, options = {}) {
2454
2455
  ([path, contents]) => sink.write(path, contents)
2455
2456
  );
2456
2457
  await purge.purgeAll();
2457
- return { ok: true, validation, written: [...byPath.keys()].sort() };
2458
+ return { ok: true, validation, written: [...byPath.keys()].sort(), summary };
2459
+ }
2460
+ function summarizeTree(root) {
2461
+ let published = 0;
2462
+ let drafts = 0;
2463
+ const walk = (node) => {
2464
+ for (const child of node.children) {
2465
+ if (child.kind === "dir") {
2466
+ walk(child);
2467
+ } else if (child.item.isPublished) {
2468
+ published += 1;
2469
+ } else {
2470
+ drafts += 1;
2471
+ }
2472
+ }
2473
+ };
2474
+ walk(root);
2475
+ if (published > 0) return { published, drafts };
2476
+ return {
2477
+ published,
2478
+ drafts,
2479
+ firstPublishWarning: drafts > 0 ? `Your site has no published pages \u2014 ${drafts} draft${drafts === 1 ? "" : "s"} were skipped. Toggle Publish on at least one page to go live.` : "Your site has no published pages. Create a page and toggle Publish on to go live."
2480
+ };
2458
2481
  }
2459
2482
  async function collectPublic(source, publicDir) {
2460
2483
  if (!await source.exists(publicDir)) return [];
@@ -140,8 +140,12 @@ interface ApiDeps {
140
140
  */
141
141
  readonly authors?: () => Promise<readonly AuthorOption[]>;
142
142
  }
143
- /** Dispatch one API request. The editor is private, so every route requires an editing
144
- * role (author/developer/admin); writes are further partitioned by path (DESIGN §11). */
143
+ /**
144
+ * Dispatch one API request. The editor is private, so every route requires an editing
145
+ * role (author/developer/admin); writes are further partitioned by path (DESIGN §11).
146
+ * Every response then passes through {@link withDefaultHeaders} so that no `/api/*`
147
+ * response is silently cached (DESIGN §13).
148
+ */
145
149
  declare function handleApi(deps: ApiDeps, req: ApiRequest): Promise<ApiResponse>;
146
150
 
147
151
  /** The byline picker's options, display name + stable handle, sorted by display name. */
@@ -212,16 +216,28 @@ declare function readMcpResource(uri: string): {
212
216
  * §11d) and bundled here as **pure data**, so the engine's purity is untouched and the
213
217
  * scaffold works identically for every host and the MCP server with no per-host wiring.
214
218
  *
215
- * Deliberately minimal (the owner's call, distinct from the fuller `examples/starter`):
216
- * one home page, a page template, the document shell, and a stylesheet. It is gate-clean
217
- * by construction no collection loops (nothing to point at yet), no custom components,
218
- * no required fields left unset so a fresh adopter can publish it immediately, and the
219
- * home page is a **draft** (`isPublished: false`) so going live is a deliberate act.
219
+ * Auto-fires on first sign-in to an empty store (revised 2026-05-28). The earlier behaviour
220
+ * a confirm prompt that the user could dismiss — left a user who said no with no path
221
+ * forward (the empty Content workspace has no signposted route to the Dev workspace, and
222
+ * every alternative to scaffolding needs templates to already exist). Removing the choice
223
+ * removes a concept; the scaffold is idempotent and gate-clean, so doing it always is safe.
224
+ *
225
+ * Deliberately minimal (revised 2026-05-28, owner's call):
226
+ * - `templates/home.html` is a **full HTML document** (DESIGN §6.10: with no
227
+ * `templates/document.html`, a page template is the whole document) — no shared shell.
228
+ * The user can extract one later when they add a second page; for the bootstrap state,
229
+ * three files is simpler than four.
230
+ * - `public/styles.css` for baseline readability — a one-page site without any CSS reads
231
+ * poorly, and the styles.css path is the editor's canonical "your site's CSS" location.
232
+ * - `content/index.json` with `isPublished: true` (revised 2026-05-28). The earlier
233
+ * "draft, so going live is deliberate" framing turned out to be a footgun: a new user
234
+ * would hit Publish and get the "nothing went live" warning without obvious cause. A
235
+ * published placeholder is honest about what a publish will do; the user's first edit
236
+ * is to replace the placeholder copy, not to also remember to toggle a flag.
220
237
  */
221
238
  /**
222
239
  * The starter files, keyed by working-store path. Written through the store's `write`
223
- * (so the index records each), in this order templates and styles before the content
224
- * that depends on them, though the store has no cross-file ordering requirement.
240
+ * (so the index records each). The store has no cross-file ordering requirement.
225
241
  */
226
242
  declare const SCAFFOLD_FILES: Readonly<Record<string, string>>;
227
243
 
@@ -8,45 +8,32 @@ import {
8
8
  loadTemplate,
9
9
  renderReferenceMarkdown,
10
10
  validateSite
11
- } from "./chunk-22WHPW5E.js";
11
+ } from "./chunk-S23S4ZAK.js";
12
12
 
13
13
  // ../editor-api/src/scaffold.ts
14
- var DOCUMENT_HTML = `<!doctype html>
14
+ var HOME_HTML = `<!doctype html>
15
15
  <html lang="en">
16
16
  <head>
17
17
  <meta charset="utf-8" />
18
18
  <meta name="viewport" content="width=device-width, initial-scale=1" />
19
19
  <title>{title}</title>
20
- <meta name="description" content="{meta_description}" />
21
20
  <link rel="stylesheet" href="/styles.css" />
22
21
  </head>
23
22
  <body>
24
- <header class="site-header">
25
- <a class="brand" href="/">Your site</a>
26
- </header>
27
23
  <main>
28
- <slot></slot>
24
+ <h1>{title}</h1>
25
+ <div class="prose" data-type="richtext">{body}</div>
29
26
  </main>
30
- <footer class="site-footer">
31
- <p>Built with nanoesis \u2014 static HTML, no runtime.</p>
32
- </footer>
33
27
  </body>
34
28
  </html>
35
29
  `;
36
- var HOME_HTML = `<section class="hero">
37
- <h1>{title}</h1>
38
- <p class="lead">{lead}</p>
39
- </section>
40
- <div class="prose" data-type="richtext">{body}</div>
41
- `;
42
30
  var HOME_JSON = `${JSON.stringify(
43
31
  {
44
32
  template: "home",
45
33
  title: "Welcome",
46
- isPublished: false,
34
+ isPublished: true,
47
35
  fields: {
48
- lead: "Edit this page in the nanoesis editor, then publish when you are ready.",
49
- body: "<p>This is your new site. It compiles to plain static HTML \u2014 there is no server and no client framework, and nothing of the editor survives into production.</p>"
36
+ body: "<p>This is your starter home page. Edit it in the nanoesis editor and click Publish to update your site.</p>"
50
37
  }
51
38
  },
52
39
  null,
@@ -67,30 +54,16 @@ body {
67
54
  margin: 0;
68
55
  }
69
56
 
70
- .site-header,
71
- main,
72
- .site-footer {
57
+ main {
73
58
  max-width: var(--max);
74
59
  margin-inline: auto;
75
60
  padding: 1.5rem 1.25rem;
76
61
  }
77
62
 
78
- .site-header .brand {
79
- font-weight: 700;
80
- text-decoration: none;
81
- color: var(--ink);
82
- }
83
-
84
- .hero h1 {
63
+ h1 {
85
64
  font-size: 2.25rem;
86
65
  letter-spacing: -0.01em;
87
- margin: 0 0 0.5rem;
88
- }
89
-
90
- .lead {
91
- font-size: 1.2rem;
92
- color: var(--muted);
93
- margin: 0 0 2rem;
66
+ margin: 0 0 1rem;
94
67
  }
95
68
 
96
69
  .prose {
@@ -100,15 +73,8 @@ main,
100
73
  a {
101
74
  color: var(--accent);
102
75
  }
103
-
104
- .site-footer {
105
- color: var(--muted);
106
- font-size: 0.9rem;
107
- border-top: 1px solid #eee;
108
- }
109
76
  `;
110
77
  var SCAFFOLD_FILES = {
111
- "templates/document.html": DOCUMENT_HTML,
112
78
  "templates/home.html": HOME_HTML,
113
79
  "public/styles.css": STYLES_CSS,
114
80
  "content/index.json": HOME_JSON
@@ -136,6 +102,14 @@ function json(status, data) {
136
102
  function methodNotAllowed() {
137
103
  return json(405, { ok: false, error: "POST only" });
138
104
  }
105
+ function withDefaultHeaders(response) {
106
+ const headers = { ...response.headers ?? {} };
107
+ if (headers["cache-control"] === void 0) {
108
+ headers["cache-control"] = "no-store";
109
+ if (headers["vary"] === void 0) headers["vary"] = "Authorization";
110
+ }
111
+ return { ...response, headers };
112
+ }
139
113
  var BEARER_PREFIX = /^Bearer\s+/i;
140
114
  function bearerToken(getHeader) {
141
115
  const raw = getHeader("authorization") ?? getHeader("Authorization");
@@ -304,6 +278,9 @@ async function handleBrandingRoute(deps, req) {
304
278
  return json(405, { ok: false, error: "method not allowed" });
305
279
  }
306
280
  async function handleApi(deps, req) {
281
+ return withDefaultHeaders(await dispatchApi(deps, req));
282
+ }
283
+ async function dispatchApi(deps, req) {
307
284
  const authResponse = await handleAuthRoute(deps, req);
308
285
  if (authResponse !== void 0) return authResponse;
309
286
  const brandingResponse = await handleBrandingRoute(deps, req);
@@ -384,8 +361,18 @@ async function handleApi(deps, req) {
384
361
  case "/api/publish": {
385
362
  if (req.method !== "POST") return methodNotAllowed();
386
363
  const result = await deps.publish();
387
- if (result.ok) return json(200, { ok: true, written: result.written.length });
388
- return json(422, { ok: false, errors: result.validation.errors.map((e) => e.message) });
364
+ if (result.ok) {
365
+ return json(200, {
366
+ ok: true,
367
+ written: result.written.length,
368
+ ...result.summary !== void 0 && { summary: result.summary }
369
+ });
370
+ }
371
+ return json(422, {
372
+ ok: false,
373
+ errors: result.validation.errors.map((e) => e.message),
374
+ ...result.summary !== void 0 && { summary: result.summary }
375
+ });
389
376
  }
390
377
  case "/api/scaffold": {
391
378
  if (req.method !== "POST") return methodNotAllowed();
package/dist/index.d.ts CHANGED
@@ -994,6 +994,24 @@ interface PublishOptions extends CompileSiteOptions {
994
994
  /** Max sink writes in flight at once (default {@link DEFAULT_WRITE_CONCURRENCY}). */
995
995
  readonly writeConcurrency?: number;
996
996
  }
997
+ /**
998
+ * What the publish actually did to *content*, as opposed to artifacts. Counts come from a
999
+ * walk of the content tree (the same definition the compiler uses, `item.isPublished`).
1000
+ * Surfaced so a host/UI can explain a publish whose written-file count looks surprising,
1001
+ * the silent first-publish footgun: a published site with no published pages.
1002
+ */
1003
+ interface PublishSummary {
1004
+ /** Content items with `isPublished: true` — the pages the publish included. */
1005
+ readonly published: number;
1006
+ /** Content items with `isPublished` false/absent — the pages the publish skipped. */
1007
+ readonly drafts: number;
1008
+ /**
1009
+ * A friendly one-liner when `published === 0`, so a UI can warn an operator who just
1010
+ * scaffolded a draft home and hit Publish that nothing went live. Absent when at least
1011
+ * one page is published.
1012
+ */
1013
+ readonly firstPublishWarning?: string;
1014
+ }
997
1015
  interface PublishResult {
998
1016
  /** True when the validation gate passed and the site was published. */
999
1017
  readonly ok: boolean;
@@ -1001,6 +1019,8 @@ interface PublishResult {
1001
1019
  readonly validation: ValidationResult;
1002
1020
  /** Output paths written to the sink, sorted; empty when validation blocked the publish. */
1003
1021
  readonly written: readonly string[];
1022
+ /** Per-content counts (the human-readable side of `written`); present when the tree loaded. */
1023
+ readonly summary?: PublishSummary;
1004
1024
  }
1005
1025
  /**
1006
1026
  * Run the Phase-1 publish pipeline (DESIGN §11) through ports: **validate → compile →
@@ -1267,4 +1287,4 @@ declare function escapeJsonStringContent(value: string): string;
1267
1287
  */
1268
1288
  declare function sanitizeUrl(url: string): string;
1269
1289
 
1270
- export { type Artifact, type ArtifactSink, type AuthEndpoints, type AuthResult, type AuthorDirectory, type AuthorEntry, type AuthorOption, type AuthorRef, type AuthoringReference, type BlobStore, type BoundItem, type ChangePasswordRequest, type ChangePasswordSuccess, type CollectionConfig, type CollectionQuery, type CompileInput, type CompilePageOptions, type CompileSiteOptions, type CompiledPage, type ComponentMap, type ContentIndex, type ContentItem, ContentParseError, type ContentSource, type CreateTokenSuccess, type CreateUserRequest, DEFAULT_DIRS, DOCUMENT_SHELL, type DerivedField, type Diagnostic, type DirEntry, type DirNode, type EncodeRequest, type EncodedImage, type EncodedVariant, type EntryKind, FIELD_TYPES, type FieldPrimitive, type FieldRecord, type FieldType, type FieldTypeDef, type FieldValue, type IdentityProvider, type ImageEncoder, type ImageFormat, type ImageInfo, InMemoryArtifactSink, InMemoryBlobStore, InMemoryContentSource, IndexedStore, type ItemNode, type LengthConstraints, type LoginRequest, type LoginSuccess, type MediaResolver, type PageEntry, type PreBuildHook, type Principal, type PublishOptions, type PublishResult, type PurgeService, RESERVED_PREFIX, type ReconcileResult, type RedirectRule, type ReferenceContext, type ReferenceEntry, type ReferenceSection, type RefreshSuccess, type RenameResult, type ResetPasswordRequest, type ResolveContext, type Role, type RssOptions, type Scope, type Severity, type SiteConfig, type SortFile, type TemplateAnalysis, type TokenContext, type TokenRef, type TreeNode, type UpdateUserRequest, type UserAdminEndpoints, type UserSummary, type ValidationResult, type ValueKind, type WorkingStore, analyzeTemplate, buildAuthoringReference, buildContentIndex, buildPictureMarkup, buildRedirects, buildResolveContext, buildRss, buildSitemap, canEdit, compilePage, compileSite, compileTemplate, contentHash, contentTypeFor, deriveFields, emptyIndex, escapeHtmlAttribute, escapeHtmlText, escapeJsonStringContent, findTokens, hasRole, humanize, inferControl, isFieldType, joinAuthors, loadComponentScripts, loadComponentStyles, loadComponents, loadContentTree, loadDocumentShell, loadIndex, loadRedirects, loadSiteConfig, loadTemplate, noopPurgeService, outputPathForItem, parseContentItem, parseRedirects, parseSortFile, processImage, publishSite, reconcileIndex, renderAuthors, renderReferenceMarkdown, sanitizeUrl, saveIndex, slugify, textContent, toAuthorRefs, urlForItem, validateSite, valueKindOf, wholeValueToken };
1290
+ export { type Artifact, type ArtifactSink, type AuthEndpoints, type AuthResult, type AuthorDirectory, type AuthorEntry, type AuthorOption, type AuthorRef, type AuthoringReference, type BlobStore, type BoundItem, type ChangePasswordRequest, type ChangePasswordSuccess, type CollectionConfig, type CollectionQuery, type CompileInput, type CompilePageOptions, type CompileSiteOptions, type CompiledPage, type ComponentMap, type ContentIndex, type ContentItem, ContentParseError, type ContentSource, type CreateTokenSuccess, type CreateUserRequest, DEFAULT_DIRS, DOCUMENT_SHELL, type DerivedField, type Diagnostic, type DirEntry, type DirNode, type EncodeRequest, type EncodedImage, type EncodedVariant, type EntryKind, FIELD_TYPES, type FieldPrimitive, type FieldRecord, type FieldType, type FieldTypeDef, type FieldValue, type IdentityProvider, type ImageEncoder, type ImageFormat, type ImageInfo, InMemoryArtifactSink, InMemoryBlobStore, InMemoryContentSource, IndexedStore, type ItemNode, type LengthConstraints, type LoginRequest, type LoginSuccess, type MediaResolver, type PageEntry, type PreBuildHook, type Principal, type PublishOptions, type PublishResult, type PublishSummary, type PurgeService, RESERVED_PREFIX, type ReconcileResult, type RedirectRule, type ReferenceContext, type ReferenceEntry, type ReferenceSection, type RefreshSuccess, type RenameResult, type ResetPasswordRequest, type ResolveContext, type Role, type RssOptions, type Scope, type Severity, type SiteConfig, type SortFile, type TemplateAnalysis, type TokenContext, type TokenRef, type TreeNode, type UpdateUserRequest, type UserAdminEndpoints, type UserSummary, type ValidationResult, type ValueKind, type WorkingStore, analyzeTemplate, buildAuthoringReference, buildContentIndex, buildPictureMarkup, buildRedirects, buildResolveContext, buildRss, buildSitemap, canEdit, compilePage, compileSite, compileTemplate, contentHash, contentTypeFor, deriveFields, emptyIndex, escapeHtmlAttribute, escapeHtmlText, escapeJsonStringContent, findTokens, hasRole, humanize, inferControl, isFieldType, joinAuthors, loadComponentScripts, loadComponentStyles, loadComponents, loadContentTree, loadDocumentShell, loadIndex, loadRedirects, loadSiteConfig, loadTemplate, noopPurgeService, outputPathForItem, parseContentItem, parseRedirects, parseSortFile, processImage, publishSite, reconcileIndex, renderAuthors, renderReferenceMarkdown, sanitizeUrl, saveIndex, slugify, textContent, toAuthorRefs, urlForItem, validateSite, valueKindOf, wholeValueToken };
package/dist/index.js CHANGED
@@ -61,7 +61,7 @@ import {
61
61
  validateSite,
62
62
  valueKindOf,
63
63
  wholeValueToken
64
- } from "./chunk-22WHPW5E.js";
64
+ } from "./chunk-S23S4ZAK.js";
65
65
  export {
66
66
  ContentParseError,
67
67
  DEFAULT_DIRS,