{"_id":"@astrolabe-ai/analytics-next","name":"@astrolabe-ai/analytics-next","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@astrolabe-ai/analytics-next","version":"1.0.0","license":"MIT","main":"./dist/cjs/index.js","module":"./dist/pkg/index.js","types":"./dist/types/index.d.ts","browser":{"./dist/cjs/node":"./dist/cjs/node/node.browser.js","./dist/cjs/node.js":"./dist/cjs/node/node.browser.js","./dist/pkg/node":"./dist/pkg/node/node.browser.js","./dist/pkg/node.js":"./dist/pkg/node/node.browser.js"},"sideEffects":false,"scripts":{"build-prep":"sh scripts/build-prep.sh","version":"yarn run build-prep && git add src/generated/version.ts","umd":"webpack","eslint":"yarn run -T eslint","tsc":"yarn run -T tsc","jest":"yarn run -T jest","concurrently":"yarn run -T concurrently","watch":"yarn concurrently 'NODE_ENV=production WATCH=true yarn umd --watch' 'yarn pkg --watch'","build":"yarn clean && yarn build-prep && NODE_ENV=production yarn umd && yarn pkg && yarn cjs","release:cdn":"yarn run -T browser+deps build && NODE_ENV=production bash scripts/release.sh && NODE_ENV=stage bash scripts/release.sh","pkg":"tsc -p tsconfig.build.json","cjs":"tsc -p tsconfig.build.json --outDir ./dist/cjs --module commonjs","clean":"rm -rf dist","lint":"yarn concurrently 'yarn:eslint .' 'yarn:tsc --noEmit'","test":"yarn jest"},"size-limit":[{"path":"dist/umd/index.js","limit":"28.0 KB"}],"dependencies":{"@lukeed/uuid":"^2.0.0","@segment/analytics-core":"1.2.2","@segment/analytics.js-video-plugins":"^0.2.1","@segment/facade":"^3.4.9","@segment/tsub":"1.0.1","dset":"^3.1.2","js-cookie":"3.0.1","node-fetch":"^2.6.7","spark-md5":"^3.0.1","tslib":"^2.4.1","typescript":"^4.9.5","unfetch":"^4.1.0"},"devDependencies":{"@segment/analytics.js-integration":"^3.3.3","@segment/analytics.js-integration-amplitude":"^3.3.3","@size-limit/preset-big-lib":"^7.0.8","@types/flat":"^5.0.1","@types/fs-extra":"^9.0.2","@types/jest-dev-server":"^5.0.0","@types/jquery":"^3.5.4","@types/js-cookie":"3.0.1","@types/jsdom":"^16.2.14","@types/mime":"^2.0.3","@types/node":"^12.12.14","@types/node-fetch":"^2.6.2","@types/serve-handler":"^6.1.0","@types/spark-md5":"^3.0.2","aws-sdk":"^2.814.0","circular-dependency-plugin":"^5.2.2","compression-webpack-plugin":"^8.0.1","execa":"^4.1.0","flat":"^5.0.2","fs-extra":"^9.0.1","jest-dev-server":"^6.0.3","jest-environment-jsdom":"^28.1.1","jquery":"^3.5.1","jsdom":"^19.0.0","lighthouse":"^9.6.3","log-update":"^4.0.0","micro-memoize":"^4.0.9","mime":"^2.4.6","node-gyp":"^9.0.0","playwright":"^1.28.1","serve-handler":"^6.1.3","size-limit":"^7.0.8","terser-webpack-plugin":"^5.1.4","ts-loader":"^9.1.1","ts-node":"^10.8.0","webpack":"^5.36.1","webpack-bundle-analyzer":"^4.4.2","webpack-cli":"^4.8.0"},"packageManager":"yarn@3.2.1","description":"- `make dev` should start a development server after a `yarn install`. - The writeKey is a valid Astrolabe API key. You can make one in interim by going into the database (`api_keys` table) and inserting a new row.","licenseText":"The MIT License (MIT)\n\nCopyright © 2021 Astrolabe\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","_id":"@astrolabe-ai/analytics-next@1.0.0","dist":{"shasum":"037fc0759403a6444954f03d2e988ed18601d8ff","integrity":"sha512-KZHWRMcUhjZ6WXMcnZaRZ8HX/q0X9kIGQ9p+s2x4lCmbx92pS8vUXDpDRt4c1zMa8IfcNJSMhn0/BAi4KIiJew==","tarball":"https://registry.npmjs.org/@astrolabe-ai/analytics-next/-/analytics-next-1.0.0.tgz","fileCount":880,"unpackedSize":4734663,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGFAdCZEufjGXwbRh5af/iud5h9c8XNBnHvLmeRB4D9aAiBmry/aZPgRPETC9Aool0t+jUXFZquG+6PoUuVF/d/j8g=="}]},"_npmUser":{"name":"samihamine","email":"haminesami@gmail.com"},"directories":{},"maintainers":[{"name":"samihamine","email":"haminesami@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/analytics-next_1.0.0_1694358474981_0.3937406507426142"},"_hasShrinkwrap":false}},"time":{"created":"2023-09-10T15:07:54.870Z","1.0.0":"2023-09-10T15:07:55.409Z","modified":"2023-09-10T15:07:55.684Z"},"maintainers":[{"name":"samihamine","email":"haminesami@gmail.com"}],"description":"- `make dev` should start a development server after a `yarn install`. - The writeKey is a valid Astrolabe API key. You can make one in interim by going into the database (`api_keys` table) and inserting a new row.","license":"MIT","readme":"This is Astrolabe's JS SDK, based on Analytics-Next by Segment.\n\n# Getting Started\n\n- `make dev` should start a development server after a `yarn install`.\n- The writeKey is a valid Astrolabe API key. You can make one in interim by going into the database (`api_keys` table) and inserting a new row.\n\n# Components\n\n- Tester (`example`): NextJS app used to generate and emit mock events to a test or production event ingress.\n- Analytics.js (`src`): Analytics library source for both brower, NodeJS\n\n# Understanding Analytics-Next\n\nTo start understanding this codebase, you need to look at a couple crucial folders within `src`:\n\n- `plugins`: analytics-next is implemented in a modular fashion, so there’s many plugins that perform separate functions.\n  - To be honest, the most important plugins are `segmentio` and `analytics-node`.\n  - The `segmentio` plugin practically handles event sending for browser clients.\n  - The `analytics-node` plugin handles event sending for Node clients.\n  - These plugins are both enabled in the entrypoint for the library, although e.g. configuration settings to both don’t necessarily get passed down to them raw.\n\n# Testing Locally\n\n## The Easy Way (Tester App)\n\nThe tester app provides a convenient way to test out small changes to the Analytics-Next codebase, reloading your changes on the fly.\n\nTo use the tester app, configure `sdk/example/config.js` and change whether to use the local or remote API.\n\nThe SDK tester app is ran automatically by Docker Compose. You should be able to visit at `localhost:3002`.\n\nThe local remote for Analytics-Node is different, as the tester is proxied via Docker. See the configuration file for more information.\n\n## Standalone Build\n\nTo change API endpoints for the standalone build, a full rebuild must be issued with the endpoint changes. There’s currently no mechanism to change apiHost on the fly (although, considering it uses the same code as the NPM build, this shouldn’t be tested separately anyways).\n\n## Browser (React, NPM)\n\nTo test the browser build, pass the `apiHost` parameter when instantiating. An example:\n\n```jsx\n// Import Astrolabe SDK:\nimport { AnalyticsBrowser } from \"@astrolabe-ai/analytics-next\";\n\n// Near the entrypoint of your app, instantiate AnalyticsBrowser:\nlet [analytics] = await AnalyticsBrowser.load({\n  writeKey: \"MY-API-KEY\",\n  apiHost: \"http://localhost:3001\",\n});\n```\n\n## Node (NPM)\n\nTo test the Node build, pass the `apiHost` and `httpScheme` parameter when instantiating. An example:\n\n```jsx\n// Import Astrolabe SDK:\nimport { AnalyticsNode } from \"@astrolabe-ai/analytics-next\";\n\n// Instantiate AnalyticsNode:\nconst [nodeAnalytics] = await AnalyticsNode.load({\n  writeKey: \"MY-KEY\",\n  httpScheme: \"http\",\n  apiHost: \"localhost:3001/sdk\",\n});\n```\n\n# Building & Publishing\n\n- The build process emits a couple of files, useful for production:\n  - The build file used in the browser script is `dist/umd/standalone.js`. With some additional code (slightly cloned) from the official Segment documentation, we can easily activate this in the client using a snippet:\n    ```jsx\n    <script>\n        window.analytics = {};\n        function astrolabeify(writeKey) {\n            window.analytics._writeKey = writeKey;\n            var script = document.createElement(\"script\");\n            script.type = \"application/javascript\";\n            script.onload = function () {\n                window.analytics.page();\n            }\n            script.src = \"https://unpkg.com/@astrolabe-ai/analytics-next/dist/umd/standalone.js\";\n            var first = document.getElementsByTagName('script')[0];\n            first.parentNode.insertBefore(script, first);\n        }\n        astrolabeify(\"API_KEY\");\n    </script>\n    ```\n  - Then there’s the NPM package, alongside any custom scripts.\n    - `scripts/sdk_release` should publish the package to NPM.\n    - You’ll need publish credentials (see https://github.com/astrolabeHQ/astrolabe/issues/2837)\n\n# Annotated Source\n\nThe core event emission code is distributed between two plugins: `segmentio` and `analytics-node`. Here are some documented changes that make `analytics-next` send events to Astrolabe:\n\n## segmentio/fetch-dispatcher.ts\n\n```jsx\nfunction dispatch(url: string, body: object): Promise<unknown> {\n  return fetch(url, {\n    headers: { \"Content-Type\": \"application/json\" }, // <----\n    method: \"post\",\n    body: JSON.stringify(body),\n  });\n}\n```\n\nAn important change from vanilla is the changing of content-type: the original Analytics-Next sends events in plaintext by default. Instead, vanilla code will silently error out.\n\n## segmentio/batched-dispatcher.ts\n\n```jsx\nexport default function batch(apiHost: string, config?: BatchingConfig) {\n...\n}\n```\n\nSome changes to note in the batched dispatcher include `application/json` content types, alongside a crucial bit: changing the `apiHost` from a hardcoded Segment API link to Astrolabe’s endpoint (around L65 and some repetitions in the file).\n\nWe’ve never seen this dispatcher used, but keep it updated for compatibility purposes. The next file is the most important for browser usage.\n\n## segmentio/index.ts\n\nThis plugin defines all visible behavior of the browser integration. This is where the critical bits lie: there are custom type definitions for Astrolabe’s SDK settings (most notably the addition of an apiHost parameter not present in vanilla).\n\n```jsx\nexport function segmentio(\n  analytics: Analytics,\n  settings?: SegmentioSettings,\n  integrations?: LegacySettings[\"integrations\"]\n): Plugin {\n  const buffer = new PersistedPriorityQueue(\n    analytics.queue.queue.maxAttempts,\n    `dest-Segment.io`\n  );\n  const flushing = false;\n\n  const apiHost = settings?.apiHost ?? \"webhook-dev.getastrolabe.com/v1/sdk\";\n  const remote = apiHost.includes(\"localhost\")\n    ? `http://${apiHost}`\n    : `https://${apiHost}`;\n\n  const client =\n    settings?.deliveryStrategy?.strategy === \"batching\"\n      ? batch(apiHost, settings?.deliveryStrategy?.config)\n      : standard();\n\n  async function send(ctx: Context): Promise<Context> {\n    if (isOffline()) {\n      buffer.push(ctx);\n      // eslint-disable-next-line @typescript-eslint/no-use-before-define\n      scheduleFlush(flushing, buffer, segmentio, scheduleFlush);\n      return ctx;\n    }\n\n    const path = ctx.event.type; //.charAt(0)\n    let json = toFacade(ctx.event).json();\n\n    if (ctx.event.type === \"track\") {\n      delete json.traits;\n    }\n\n    if (ctx.event.type === \"alias\") {\n      json = onAlias(analytics, json);\n    }\n\n    return client\n      .dispatch(\n        `${remote}/${path}`,\n        normalize(analytics, json, settings, integrations)\n      )\n      .then(() => ctx)\n      .catch((err) => {\n        if (err.type === \"error\" || err.message === \"Failed to fetch\") {\n          buffer.push(ctx);\n          // eslint-disable-next-line @typescript-eslint/no-use-before-define\n          scheduleFlush(flushing, buffer, segmentio, scheduleFlush);\n        }\n        return ctx;\n      });\n  }\n\n  const segmentio: Plugin = {\n    name: \"Segment.io\",\n    type: \"after\",\n    version: \"0.1.0\",\n    isLoaded: (): boolean => true,\n    load: (): Promise<void> => Promise.resolve(),\n    track: send,\n    identify: send,\n    page: send,\n    alias: send,\n    group: send,\n  };\n\n  return segmentio;\n}\n```\n\nAside from configuration changes, the most important line that enables sending to our SDK endpoints is the following:\n\n```jsx\nconst apiHost = settings?.apiHost ?? \"webhook-dev.getastrolabe.com/v1/sdk\";\nconst remote = apiHost.includes(\"localhost\")\n  ? `http://${apiHost}`\n  : `https://${apiHost}`;\n```\n\nWhen passing in settings and initializing the SDK, you can pass an apiHost to test locally. This also works with the tester app.\n\n## analytics-node/index.ts\n\nMost changes to this SDK are almost identical to the browser changes (content-type, etc).\n\nThe Node SDK has some modifications in the type signature for configuration parameters: most notably (and usefully), you can pass in an apiHost and httpScheme. This allows for local testing.\n\n## standalone.ts & standalone-analytics.ts\n\nThese files contain the code that gets run for the Standalone build (that is, the script tag we provide for easy installs).\n\nThe most important thing to make sure when loading the browser script is to initialize [`window.analytics`](http://window.analytics) to an empty object and then set `window.analytics._writeKey` with the API key.\n\n## analytics.ts\n\nThis file contains the API surface for the analytics package, which is standard (the only thing that changes is the underlying dispatcher).\n\n## analytics-node.ts & browser.ts\n\nThis file contains the modules imported when the NPM package is installed. There’s some modified type signatures, in particular to make sure passing an `httpScheme` and `apiHost` is allowed.\n","readmeFilename":"README.md"}