Skip to content

Feature/plugins#31

Merged
magmacomputing merged 9 commits into
mainfrom
feature/plugins
May 22, 2026
Merged

Feature/plugins#31
magmacomputing merged 9 commits into
mainfrom
feature/plugins

Conversation

@magmacomputing
Copy link
Copy Markdown
Owner

@magmacomputing magmacomputing commented May 22, 2026

Summary by CodeRabbit

  • New Features

    • Global browser-context license discovery; user-facing license snapshot with formatted timestamps and sensitive-field redaction; improved term lookup indexing; Free Showcase Astronomical Seasons plugin; enhanced build banner.
  • Documentation

    • Expanded license application flows, network/offline behavior, log-stamp format, and relative time/duration examples.
  • Bug Fixes / Security

    • License snapshot resilience, cross-platform build determinism, env override support, JWT key redaction and runtime guards.
  • Tests

    • Updated license discovery and runtime license tests.
  • Chores

    • Version bumped to 2.10.1.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0dcf89a5-eb9c-4a8c-88d6-0e785d2e4c9f

📥 Commits

Reviewing files that changed from the base of the PR and between 32473aa and f6e44e3.

📒 Files selected for processing (1)
  • packages/tempo/CHANGELOG.md
✅ Files skipped from review due to trivial changes (1)
  • packages/tempo/CHANGELOG.md

📝 Walkthrough

Walkthrough

This PR refactors Tempo's licensing system to support JWT-based permission scopes, updates the license discovery cascade, and introduces a new indexedArray utility for proxy-based array indexing. The public Tempo.license API now returns a formatted user-facing snapshot instead of raw internal state, while the terms registry gains scope-aware indexing. Documentation and test coverage are expanded accordingly.

Changes

Licensing System and Indexing Improvements

Layer / File(s) Summary
Indexing utilities and environment support
packages/library/src/common/proxy.library.ts, packages/library/src/common/storage.library.ts
New indexedArray helper wraps arrays via delegate and routes non-numeric string property accesses to a finder callback. Storage utilities now support the CONTEXT.Deno environment by reading/writing via context.global.Deno.env.
License JWT validation and scope extraction
packages/tempo/src/support/support.license.ts
License validator imports decodeJWT and now extracts permission claims from the JWT token, populating a scopes map from decoded claims.permissions instead of returning an empty map.
License discovery cascade and initialization
packages/tempo/src/support/support.init.ts
License initialization fallback logic updated to use options.license, then getStorage('TEMPO_LICENSE_KEY'), then globalThis.TEMPO_LICENSE_KEY, removing legacy TEMPO_LICENSE/__TEMPO_DISCOVERY__ lookups.
Public API transformation for license and terms
packages/tempo/src/tempo.class.ts
Tempo.license static getter now returns a secure, user-facing snapshot that omits internal jws/key and converts numeric JWT timestamps (exp, updated_at, expires, issuedAt) to formatted week-time strings via Tempo formatting. Tempo.terms registry switched from delegate to indexedArray for scope-aware term indexing.
License discovery and environment test coverage
packages/tempo/test/plugins/licensing.full.test.ts
Test suite adds per-test environment isolation for process.env.TEMPO_LICENSE_KEY. New discovery cascade tests verify that Tempo.init() picks up licenses from globalThis.TEMPO_LICENSE_KEY and process.env.TEMPO_LICENSE_KEY, asserting runtime license key and permission scopes.
Version bumps, build scripts, and type resolution
package.json, packages/library/package.json, packages/tempo/package.json, packages/tempo/bin/resolve-types.ts
Root and Tempo versions bumped to 2.10.1; @magmacomputing/library dependency updated to 2.10.1. New repl:dist npm script added; post-build license file validation removed. resolve-types.ts now requires the external @core license d.ts path to exist.
Documentation updates for licensing and consistency
packages/tempo/doc/tempo.license.md, packages/tempo/doc/tempo.cookbook.md, packages/tempo/doc/comparison.md, packages/tempo/doc/tempo-vs-temporal.md, packages/tempo/doc/releases/v2.x.md, packages/tempo/CHANGELOG.md, packages/tempo/rollup.config.js
License documentation expanded with website-based key request flow, programmatic plugin provisioning via Tempo.init({ plugins: [...] }), globalThis fallback guidance, and revocation-list sync behavior. Cookbook headings standardized to "and". Comparison and temporal docs updated with logStamp and until/since examples; release notes and rollup banner updated.

Sequence Diagram(s)

sequenceDiagram
  participant App as Application Code
  participant InitFlow as Tempo.init()
  participant Discover as License Discovery
  participant Validator as Validator.verify()
  participant Runtime as Runtime State

  App->>InitFlow: call init({ license?: string })
  InitFlow->>Discover: check options.license
  alt no options.license
    Discover->>Discover: check process.env.TEMPO_LICENSE_KEY
    alt no env key
      Discover->>Discover: check globalThis.TEMPO_LICENSE_KEY
    end
  end
  Discover->>Validator: setLicense(state, discoveredKey)
  Validator->>Validator: decodeJWT(key) -> claims.permissions
  Validator->>Runtime: populate scopes and store license
  Runtime->>App: Tempo.license (user-facing snapshot with formatted timestamps)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • magmacomputing/magma#30: Both PRs modify Tempo's licensing implementation in the core license discovery (packages/tempo/src/support/support.init.ts) and JWT verification (packages/tempo/src/support/support.license.ts) areas, directly related at the code level.
  • magmacomputing/magma#9: Touches the terms-registry surface and proxy utilities; related to the swap to indexedArray and terms indexing behavior.

Poem

🐰 A licensing leap, permissions now decoded,
JWT whispers tell the scopes they've showed,
Arrays index sharp with finder-led delight,
A user-safe snapshot keeps secrets out of sight,
Deno waves hello as docs and tests take flight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title "Feature/plugins" is vague and generic, using branch naming conventions rather than describing the actual changes in the pull request. Replace with a specific, descriptive title that captures the main change, such as "Add license key discovery and improve terms registry indexing" or "Support global license context and premium plugin configuration."
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/plugins

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/tempo/bin/resolve-types.ts`:
- Line 16: Change LIC_SRC_DIR to be resolved relative to the script file instead
of process.cwd by using __dirname (e.g. path.resolve(__dirname,
'../../../tempo-plugin/internal/@core/dist') or path.join(__dirname, '..', '..',
'..', 'tempo-plugin', 'internal', '`@core`', 'dist')) and then immediately verify
the directory exists (fs.existsSync) before proceeding; if it does not exist,
log an explicit error and process.exit(1) so the code does not silently fall
back to the minimal license typings referenced later in the script (the
LIC_SRC_DIR constant and the minimal-types fallback section).

In `@packages/tempo/doc/tempo-vs-temporal.md`:
- Around line 85-97: The examples use dynamic now() by instantiating new Tempo()
and assert exact outputs which will drift; make them deterministic by
constructing Tempo with a fixed anchor datetime (e.g., pass an explicit
reference date or use a Tempo.from/Tempo.withAnchor helper) so
Tempo().fmt.logStamp and expressions like until('xmas', ...) produce stable
output in docs—update the examples that call Tempo, Tempo.init, .fmt.logStamp
and until(...) to create the Tempo instance from a fixed Date/time value so the
demonstrated outputs remain constant.

In `@packages/tempo/src/support/support.init.ts`:
- Around line 135-138: The change removed legacy fallbacks for TEMPO_LICENSE
causing downstream breakage; restore the older fallbacks while keeping
TEMPO_LICENSE_KEY precedence: in the initialization logic around the variable
key (calls to getStorage and globalThis), ensure you first try
getStorage('TEMPO_LICENSE_KEY') and (globalThis as any).TEMPO_LICENSE_KEY, then
if still falsy fall back to getStorage('TEMPO_LICENSE') and (globalThis as
any).TEMPO_LICENSE respectively so both legacy and new env keys are supported
(locate this logic by looking for getStorage and TEMPO_LICENSE_KEY /
TEMPO_LICENSE references).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 679ec555-7fa6-45d5-8563-82de01037b70

📥 Commits

Reviewing files that changed from the base of the PR and between ca0ac7f and f3e4928.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (14)
  • package.json
  • packages/library/package.json
  • packages/library/src/common/proxy.library.ts
  • packages/library/src/common/storage.library.ts
  • packages/tempo/bin/resolve-types.ts
  • packages/tempo/doc/comparison.md
  • packages/tempo/doc/tempo-vs-temporal.md
  • packages/tempo/doc/tempo.cookbook.md
  • packages/tempo/doc/tempo.license.md
  • packages/tempo/package.json
  • packages/tempo/src/support/support.init.ts
  • packages/tempo/src/support/support.license.ts
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/test/plugins/licensing.full.test.ts

Comment thread packages/tempo/bin/resolve-types.ts Outdated
Comment thread packages/tempo/doc/tempo-vs-temporal.md
Comment thread packages/tempo/src/support/support.init.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/tempo/src/tempo.class.ts (1)

99-110: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard raw.scopes before iterating in Tempo.license.

If raw.scopes is missing or non-object, Line 102 can throw and break the public license getter. Normalize it before Object.entries(...).

Suggested patch
 	static get license() {
 		const { jws, key, ...raw } = Tempo.#license;						// omit internal Pledge and JWT string from user-facing snapshot
 		const ss = { timeStamp: 'ss' } as const;								// JWT timestamps are always in seconds (RFC 7519)
+		const rawScopes = isObject(raw.scopes) ? raw.scopes as Record<string, any> : {};
 		const scopes = Object.fromEntries(
-			Object.entries(raw.scopes).map(([key, scope]) => {
+			Object.entries(rawScopes).map(([key, scope]) => {
 				const s = scope as any;
 				return [key, {
 					...s,
 					...(typeof s.exp === 'number' && { exp: new Tempo(s.exp, ss).fmt.weekTime }),
 					...(typeof s.updated_at === 'number' && { updated_at: new Tempo(s.updated_at, ss).fmt.weekTime }),
 				}];
 			})
 		);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tempo/src/tempo.class.ts` around lines 99 - 110, The public license
snapshot generation uses raw.scopes without guarding it, which can throw when
raw.scopes is missing or not an object; update the Tempo.license getter (where
Tempo.#license is destructured and scopes is computed) to normalize/guard
raw.scopes before iterating — e.g., set const scopesSource = (raw.scopes &&
typeof raw.scopes === 'object') ? raw.scopes : {} and then run
Object.entries(scopesSource).map(...), preserving the existing mapping that uses
new Tempo(...).fmt.weekTime for exp and updated_at so callers never hit an
exception when scopes is absent or invalid.
♻️ Duplicate comments (1)
packages/tempo/bin/resolve-types.ts (1)

16-16: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix Windows/URL path handling in packages/tempo/bin/resolve-types.ts

  • new URL(import.meta.url).pathname can break path handling on Windows (URL encoding / drive-letter quirks); use fileURLToPath(import.meta.url) (or import.meta.dirname on newer Node) instead.
  • The hard-fail for missing LIC_SRC_DIR and the follow-up simplified license copy logic are consistent and good.
  • Optional: allow overriding LIC_SRC_DIR via env var for local/dev environments.
🔧 Proposed fix
 import fs from 'node:fs';
 import path from 'node:path';
+import { fileURLToPath } from 'node:url';

-const __dirname = path.dirname(new URL(import.meta.url).pathname);
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
 const LIC_SRC_DIR = path.resolve(__dirname, '../../../../tempo-plugin/internal/@core/dist');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tempo/bin/resolve-types.ts` at line 16, Replace the fragile
URL-based dirname computation that uses "const __dirname = path.dirname(new
URL(import.meta.url).pathname);" with Node's fileURLToPath(import.meta.url) to
derive __dirname safely on Windows (i.e., compute __dirname via
path.dirname(fileURLToPath(import.meta.url))). Also update imports to include
fileURLToPath from "url" if missing. While here, make LIC_SRC_DIR read from
process.env.LIC_SRC_DIR with the existing hard-fail fallback so local/dev
overrides are possible (keep the same failure behavior when not provided).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/tempo/src/tempo.class.ts`:
- Around line 99-110: The public license snapshot generation uses raw.scopes
without guarding it, which can throw when raw.scopes is missing or not an
object; update the Tempo.license getter (where Tempo.#license is destructured
and scopes is computed) to normalize/guard raw.scopes before iterating — e.g.,
set const scopesSource = (raw.scopes && typeof raw.scopes === 'object') ?
raw.scopes : {} and then run Object.entries(scopesSource).map(...), preserving
the existing mapping that uses new Tempo(...).fmt.weekTime for exp and
updated_at so callers never hit an exception when scopes is absent or invalid.

---

Duplicate comments:
In `@packages/tempo/bin/resolve-types.ts`:
- Line 16: Replace the fragile URL-based dirname computation that uses "const
__dirname = path.dirname(new URL(import.meta.url).pathname);" with Node's
fileURLToPath(import.meta.url) to derive __dirname safely on Windows (i.e.,
compute __dirname via path.dirname(fileURLToPath(import.meta.url))). Also update
imports to include fileURLToPath from "url" if missing. While here, make
LIC_SRC_DIR read from process.env.LIC_SRC_DIR with the existing hard-fail
fallback so local/dev overrides are possible (keep the same failure behavior
when not provided).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2cd031be-3539-4f42-b5d4-8400aba26c4c

📥 Commits

Reviewing files that changed from the base of the PR and between f3e4928 and fa3a246.

📒 Files selected for processing (7)
  • packages/tempo/bin/resolve-types.ts
  • packages/tempo/doc/releases/v2.x.md
  • packages/tempo/doc/tempo-vs-temporal.md
  • packages/tempo/rollup.config.js
  • packages/tempo/src/support/support.init.ts
  • packages/tempo/src/tempo.class.ts
  • packages/tempo/test/plugins/licensing.full.test.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/tempo/rollup.config.js
  • packages/tempo/doc/releases/v2.x.md

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/tempo/CHANGELOG.md (1)

18-18: 💤 Low value

Consider simplifying "prior to" to "before" for better readability.

The phrase "prior to iteration" could be shortened to "before iteration" for more concise user-facing documentation.

📝 Suggested simplification
-- **License Snapshot Resilience**: Implemented a safety guard in `Tempo.license` to normalize `raw.scopes` prior to iteration, eliminating potential runtime exceptions when scopes are absent.
+- **License Snapshot Resilience**: Implemented a safety guard in `Tempo.license` to normalize `raw.scopes` before iteration, eliminating potential runtime exceptions when scopes are absent.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/tempo/CHANGELOG.md` at line 18, The changelog sentence under
"License Snapshot Resilience" uses the phrase "prior to iteration"; update the
text so it reads "before iteration" to improve readability—locate the entry
referencing Tempo.license and the line that says "normalize `raw.scopes` prior
to iteration" and replace "prior to" with "before".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/tempo/CHANGELOG.md`:
- Line 18: The changelog sentence under "License Snapshot Resilience" uses the
phrase "prior to iteration"; update the text so it reads "before iteration" to
improve readability—locate the entry referencing Tempo.license and the line that
says "normalize `raw.scopes` prior to iteration" and replace "prior to" with
"before".

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e018b753-7655-42b7-aa19-1f87be208eb6

📥 Commits

Reviewing files that changed from the base of the PR and between fa3a246 and 32473aa.

📒 Files selected for processing (3)
  • packages/tempo/CHANGELOG.md
  • packages/tempo/bin/resolve-types.ts
  • packages/tempo/src/tempo.class.ts

@magmacomputing magmacomputing merged commit 4010807 into main May 22, 2026
2 checks passed
@magmacomputing magmacomputing deleted the feature/plugins branch May 22, 2026 09:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant