Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,10 @@ Thumbs.db
**/.vitepress/cache/
**/.vitepress/dist/
**/doc/api/

# Secrets and credentials
.env
.env.*
.npmrc.local
.npmrc
!.npmrc
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,24 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [2.10.0] - 2026-05-11

### Added
- **Licensing Architecture Preparation**: Initial work to support licensed plugins and features.

### Changed
- **Term Collision Enforcement**: Term plugin registration now throws a fatal error on naming collisions (key/scope) to prevent silent configuration failures.

## [2.9.3] - 2026-05-11

### Added
- **Fractional Resolution**: Numeric inputs now support fractional components with nanosecond precision using BigInt math.
- **Hardened AliasContext**: Improved chainable context for functional aliases with full API parity.
- **Epoch Support**: Enhanced detection for 9-10 digit Epoch timestamps.

### Fixed
- **Mutation Safety**: Eliminated side-effects on global configuration during parsing.
- **Normalizer Memory**: Fixed state leakage in alias resolution.

## [2.8.0] - 2026-04-30

Expand Down
2,288 changes: 1,575 additions & 713 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tempo-monorepo",
"version": "2.9.3",
"version": "2.10.0",
"private": true,
"description": "Magma Computing Monorepo",
"repository": {
Expand All @@ -26,16 +26,16 @@
"devDependencies": {
"@js-temporal/polyfill": "^0.5.1",
"@rollup/plugin-node-resolve": "^16.0.3",
"@types/google.maps": "^3.64.0",
"@types/google.maps": "^3.64.1",
"@types/hammerjs": "^2.0.46",
"@types/jquery": "^4.0.0",
"@types/node": "^25.6.2",
"@types/node": "^25.8.0",
"@vitest/ui": "^2.1.9",
"cross-env": "^10.1.0",
"markdown-it-mathjax3": "^4.3.2",
"rollup": "^4.60.3",
"rollup": "^4.60.4",
"tslib": "^2.8.1",
"tsx": "^4.21.0",
"tsx": "^4.22.0",
"typescript": "^6.0.3",
"vitest": "^2.1.9"
},
Expand Down
21 changes: 21 additions & 0 deletions packages/library/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Magma Computing

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
5 changes: 4 additions & 1 deletion packages/library/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@magmacomputing/library",
"version": "2.9.3",
"version": "2.10.0",
"description": "Shared utility library for Tempo",
"author": "Magma Computing Solutions",
"license": "MIT",
Expand All @@ -9,6 +9,9 @@
"url": "git+https://github.com/magmacomputing/magma.git",
"directory": "packages/library"
},
"publishConfig": {
"access": "public"
},
"homepage": "https://github.com/magmacomputing/magma/tree/main/packages/library#readme",
"bugs": {
"url": "https://github.com/magmacomputing/magma/issues"
Expand Down
7 changes: 4 additions & 3 deletions packages/library/src/common/storage.library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ export function getStorage<T>(key?: string, dflt?: T): T | undefined {

case CONTEXT.NodeJS:
store = context.global.process.env[key];
if (key === '$Tempo' && !store) {
// skip debug log for production/test clean-up
}
break;

case CONTEXT.Deno:
store = context.global.Deno.env.get(key);
break;

case CONTEXT.GoogleAppsScript:
Expand Down
31 changes: 30 additions & 1 deletion packages/library/src/common/utility.library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,32 @@ import type { Secure, ValueOf } from '#library/type.library.js';

/** General utility functions */

/** fast, unverified decode of a JWT payload */
export const decodeJWT = <T = any>(jwt: string): T | null => {
try {
const part = jwt.split('.')[1];
if (!part) return null;
// 🛡️ Base64URL Normalization: replace -/_ with +/ and add padding
const base64 = part.replace(/-/g, '+').replace(/_/g, '/').padEnd(part.length + (4 - part.length % 4) % 4, '=');
const payload = typeof atob === 'function' ? atob(base64) : Buffer.from(base64, 'base64').toString();
return JSON.parse(payload);
} catch { return null; }
}

/** portable base64 encoder for universal support */
export const base64Encode = (input: string): string => {
if (typeof Buffer !== 'undefined')
return Buffer.from(input).toString('base64');

const bytes = new TextEncoder().encode(input);
let binary = '';

for (let i = 0; i < bytes.byteLength; i++)
binary += String.fromCharCode(bytes[i]);

return btoa(binary);
}

/** analyze the Call Stack to determine calling Function's name */
export const getCaller = () => {
const stackTrace = new Error().stack // only tested in latest FF and Chrome
Expand Down Expand Up @@ -58,6 +84,9 @@ export const getContext = (): Context => {
if (isDefined(global.window?.document))
return { global, type: CONTEXT.Browser };

if (isDefined(global.Deno))
return { global, type: CONTEXT.Deno };

if (isDefined(global.process?.versions?.node))
return { global, type: CONTEXT.NodeJS };

Expand Down Expand Up @@ -85,7 +114,7 @@ export function deepFreeze<const T extends object>(obj: T, options?: { skip?: We
export function deepFreeze<const T extends object>(obj: T, options?: { skip?: WeakSet<object> } | WeakSet<object>, seen: WeakSet<object> = new WeakSet<object>()): Secure<T> {
// Support both old and new signatures for backward compatibility
const skip = (options instanceof WeakSet) ? options : (options?.skip ?? EMPTY_SKIP);

if (isPrimitive(obj) || Object.isFrozen(obj) || seen.has(obj) || skip.has(obj))
return obj as Secure<T>;

Expand Down
1 change: 1 addition & 0 deletions packages/library/src/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"composite": true,
"lib": [
"ESNext",
"ESNext.Temporal",
"DOM"
],
"types": [
Expand Down
6 changes: 0 additions & 6 deletions packages/library/test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@
],
"#server/*": [
"../src/server/*"
],
"#tempo": [
"../../tempo/src/tempo.index.ts"
],
"#tempo/*": [
"../../tempo/src/*"
]
}
},
Expand Down
6 changes: 0 additions & 6 deletions packages/library/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@
],
"#server/*": [
"./src/server/*"
],
"#tempo": [
"../tempo/src/tempo.index.ts"
],
"#tempo/*": [
"../tempo/src/*"
]
}
},
Expand Down
12 changes: 12 additions & 0 deletions packages/tempo/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.10.0] - 2026-05-11

### Added
- **Licensing Architecture**: Implemented a standalone "No-Op" licensing engine (`support.license.ts`) in the public core. This ensures the repository is 100% buildable and testable by the community without private dependencies.
- **Automatic Premium Injection**: Optimized the build pipeline (Rollup/Vitest) to automatically detect and inject the proprietary licensing engine from a side-by-side repository during official builds.
- **Portable Encoding**: Migrated `base64Encode` to the shared library for universal, environment-agnostic token handling.

### Changed
- **Hardened Licensing Resolution**: Updated the term resolution pipeline with a dual-identity race-condition guard (JTI + Key) and a late-binding resolution guard to securely handle `Pending` to `Revoked` state transitions.
- **Decoupled CI Resolution**: Eliminated the need for private registries or stubs in GitHub Actions by utilizing the internal No-Op engine for standard test runs.
- **Term Collision Enforcement**: Term plugin registration now throws a fatal error on naming collisions (key/scope) to prevent silent configuration failures.

## [2.9.3] - 2026-05-11

### Added
Expand Down
26 changes: 25 additions & 1 deletion packages/tempo/bin/resolve-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const DIST_DIR = path.resolve('dist');
const LIB_SRC_DIR = path.resolve('../library/dist/common');
const LIB_DEST_DIR = path.resolve(DIST_DIR, 'lib');

const LIC_SRC_DIR = path.resolve('../../../tempo-plugin/packages/@core/dist');
const LIC_DEST_DIR = path.resolve(DIST_DIR, 'lic');
Comment thread
magmacomputing marked this conversation as resolved.

console.log('Resolving type definitions...');

// 1. Ensure lib directory exists
Expand All @@ -34,6 +37,15 @@ usedModules.forEach(mod => {
}
});

// 4. Copy licensing core types
if (fs.existsSync(LIC_SRC_DIR)) {
if (!fs.existsSync(LIC_DEST_DIR)) fs.mkdirSync(LIC_DEST_DIR, { recursive: true });
const licFiles = fs.readdirSync(LIC_SRC_DIR).filter(f => f.endsWith('.d.ts'));
licFiles.forEach(file => {
fs.copyFileSync(path.join(LIC_SRC_DIR, file), path.join(LIC_DEST_DIR, file));
});
}

// 4. Walk through all .d.ts files in dist/ to rewrite aliases
function walk(dir: string) {
const files = fs.readdirSync(dir);
Expand Down Expand Up @@ -64,6 +76,17 @@ function rewrite(filePath: string) {
replacement = `${prefix || './'}lib/`;
}

// Handle #tempo/license resolution
let licReplacement: string;
const isInsideLic = relToDist.startsWith('lic');
if (isInsideLic) {
licReplacement = './';
} else {
let prefix = '';
for (let i = 0; i < depth; i++) prefix += '../';
licReplacement = `${prefix || './'}lic/`;
}

const updatedContent = content
.replace(/#library\/([^"')]+\.js)/g, (match, libPath) => {
// NOTE: We use path.basename here because the @magmacomputing/library distribution
Expand All @@ -72,7 +95,8 @@ function rewrite(filePath: string) {
const fileName = path.basename(libPath);
return `${replacement}${fileName}`;
})
.replace(/#library(['"])/g, (match, quote) => `${replacement}index.js${quote}`);
.replace(/#library(['"])/g, (match, quote) => `${replacement}index.js${quote}`)
.replace(/#tempo\/license(['"])/g, (match, quote) => `${licReplacement}index.js${quote}`);

if (content !== updatedContent) {
fs.writeFileSync(filePath, updatedContent);
Expand Down
17 changes: 17 additions & 0 deletions packages/tempo/doc/releases/v2.x.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# 📜 Version 2.x History

## [v2.10.0] = 2026-05-20
### New Features

- Added licensing system with JWT validation and revocation checks
- Introduced Tempo.license public API for license state management
- Enhanced terms display with license metadata support
- Term registration now enforces naming collision detection

### Bug Fixes

- Fixed parsing side-effects and state leakage issues
- Improved epoch timestamp precision with nanosecond-level fractional resolution for 9–10 digit timestamps

### Documentation
- Comprehensive licensing architecture and strategy documentation added.
- Added guidance for CI-safe licensing stubs and cross-repo dependency management.

## [v2.9.3] - 2026-05-10
### 🏗️ Engine Stabilization & Hardening
- **Timestamp Resolution Fix**: Corrected configuration propagation for `timeStamp` settings, ensuring consistent persistence across nested Tempo instances.
Expand Down
17 changes: 12 additions & 5 deletions packages/tempo/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@magmacomputing/tempo",
"version": "2.9.3",
"version": "2.10.0",
"description": "The Tempo core library",
"author": "Magma Computing Solutions",
"license": "MIT",
Expand All @@ -21,6 +21,9 @@
"fluent",
"parsing"
],
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"type": "module",
"sideEffects": [
"**/tempo.index.js",
Expand Down Expand Up @@ -113,6 +116,7 @@
"development": "./src/module/module.index.ts",
"default": "./dist/module/module.index.js"
},
"#tempo/license": "./src/support/support.license.ts",
Comment thread
magmacomputing marked this conversation as resolved.
Outdated
"#tempo/*.js": {
"development": "./src/*.ts",
"default": "./dist/*.js"
Expand Down Expand Up @@ -199,12 +203,12 @@
"bare": "tsx --conditions=development -i --harmony-temporal",
"core": "cross-env TEMPO_LITE=true tsx --conditions=development -i --harmony-temporal --import ./bin/core.ts",
"parse": "cross-env TEMPO_LITE=true tsx --conditions=development -i --harmony-temporal --import ./bin/parse.ts",
"build": "npm run clean && tsc -b && npm run build:bundle && npm run build:resolve",
"build": "npm run clean && tsc -b && npm run build:bundle && npm run build:resolve && if [ ! -f dist/lic/index.js ]; then echo '🚨 ERROR: dist/lic/index.js is missing from dist!'; exit 1; fi",
"build:bundle": "rollup -c",
"build:resolve": "tsx bin/resolve-types.ts",
"clean": "rm -rf dist && (tsc -b --clean || true)",
"publish": "npm publish --access public",
"prepublishOnly": "if [ $(git rev-parse --abbrev-ref HEAD) != main ]; then echo 'ERROR: Must be on main branch to publish.'; exit 1; fi && npm run build",
"prepublishOnly": "if [ $(git rev-parse --abbrev-ref HEAD) != main ]; then echo 'ERROR: Must be on main branch to publish.'; exit 1; fi && if [ -z \"$TEMPO_LICENSE_PATH\" ] || [ ! -f \"$TEMPO_LICENSE_PATH\" ]; then echo '🚨 ERROR: TEMPO_LICENSE_PATH is missing or invalid. Cannot publish Premium build.'; exit 1; fi && npm run build",
"docs:api": "typedoc",
"docs:dev": "npm run build && npm run docs:api && vitepress dev",
"docs:build": "npm run build && npm run docs:api && vitepress build",
Expand All @@ -219,9 +223,12 @@
},
"devDependencies": {
"@js-temporal/polyfill": "^0.5.1",
"@magmacomputing/library": "2.9.3",
"@magmacomputing/library": "2.10.0",
"@rollup/plugin-alias": "^6.0.0",
"esbuild": "^0.25.12",
"javascript-obfuscator": "^5.4.2",
"magic-string": "^0.30.21",
"rollup-plugin-esbuild": "^6.2.1",
"typedoc": "^0.28.19",
"typedoc-plugin-markdown": "^4.11.0",
"typedoc-vitepress-theme": "^1.1.2",
Expand All @@ -231,4 +238,4 @@
"doc": "doc",
"test": "test"
}
}
}
Loading
Loading